Merge "Improve CtsApiCoverage error message for missing testApk files" am: 4d6b7740b9 am: 25a7f03ae9 am: 0caad068db
am: 8ead43a8f0
Change-Id: I71eb7c0894d1cada7d2791c27fa5a0aaf4aa7d67
diff --git a/apps/CameraITS/pymodules/its/cv2image.py b/apps/CameraITS/pymodules/its/cv2image.py
index 83e654e..a34d4ce 100644
--- a/apps/CameraITS/pymodules/its/cv2image.py
+++ b/apps/CameraITS/pymodules/its/cv2image.py
@@ -12,27 +12,36 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import matplotlib
-matplotlib.use('Agg')
-
-import its.error
-from matplotlib import pylab
-import sys
-from PIL import Image
-import numpy
-import math
-import unittest
-import cStringIO
-import scipy.stats
-import copy
-import cv2
import os
+import unittest
+
+import cv2
+import its.device
+import its.error
+import numpy
+
+VGA_HEIGHT = 480
+VGA_WIDTH = 640
+
def scale_img(img, scale=1.0):
"""Scale and image based on a real number scale factor."""
dim = (int(img.shape[1]*scale), int(img.shape[0]*scale))
return cv2.resize(img.copy(), dim, interpolation=cv2.INTER_AREA)
+
+def gray_scale_img(img):
+ """Return gray scale version of image."""
+ if len(img.shape) == 2:
+ img_gray = img.copy()
+ elif len(img.shape) == 3:
+ if img.shape[2] == 1:
+ img_gray = img[:, :, 0].copy()
+ else:
+ img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
+ return img_gray
+
+
class Chart(object):
"""Definition for chart object.
@@ -57,6 +66,9 @@
self._scale_start = scale_start
self._scale_stop = scale_stop
self._scale_step = scale_step
+ self.xnorm, self.ynorm, self.wnorm, self.hnorm, self.scale = its.image.chart_located_per_argv()
+ if not self.xnorm:
+ self.locate()
def _calc_scale_factors(self, cam, props, fmt, s, e, fd):
"""Take an image with s, e, & fd to find the chart location.
@@ -79,7 +91,7 @@
req['android.lens.focusDistance'] = fd
cap_chart = its.image.stationary_lens_cap(cam, req, fmt)
img_3a = its.image.convert_capture_to_rgb_image(cap_chart, props)
- img_3a = its.image.flip_mirror_img_per_argv(img_3a)
+ img_3a = its.image.rotate_img_per_argv(img_3a)
its.image.write_image(img_3a, 'af_scene.jpg')
template = cv2.imread(self._file, cv2.IMREAD_ANYDEPTH)
focal_l = cap_chart['metadata']['android.lens.focalLength']
@@ -95,8 +107,15 @@
print 'Chart/image scale factor = %.2f' % scale_factor
return template, img_3a, scale_factor
- def locate(self, cam, props, fmt, s, e, fd):
- """Find the chart in the image.
+ def locate(self, cam=None, props=None, fmt=None, s=0, e=0, fd=0):
+ """Find the chart in the image, and append location to chart object.
+
+ The values appended are:
+ xnorm: float; [0, 1] left loc of chart in scene
+ ynorm: float; [0, 1] top loc of chart in scene
+ wnorm: float; [0, 1] width of chart in scene
+ hnorm: float; [0, 1] height of chart in scene
+ scale: float; scale factor to extract chart
Args:
cam: An open device session
@@ -107,29 +126,30 @@
e: Exposure time for the AF request as defined in
android.sensor.exposureTime
fd: float; autofocus lens position
-
- Returns:
- xnorm: float; [0, 1] left loc of chart in scene
- ynorm: float; [0, 1] top loc of chart in scene
- wnorm: float; [0, 1] width of chart in scene
- hnorm: float; [0, 1] height of chart in scene
"""
- chart, scene, s_factor = self._calc_scale_factors(cam, props, fmt,
- s, e, fd)
+ if cam:
+ chart, scene, s_factor = self._calc_scale_factors(cam, props, fmt,
+ s, e, fd)
+ else:
+ with its.device.ItsSession() as cam:
+ props = cam.get_camera_properties()
+ fmt = {'format': 'yuv', 'width': VGA_WIDTH,
+ 'height': VGA_HEIGHT}
+
+ # Get sensitivity, exposure time, and focus distance with 3A.
+ s, e, _, _, fd = cam.do_3a(get_results=True)
+
+ chart, scene, s_factor = self._calc_scale_factors(cam, props,
+ fmt, s, e, fd)
scale_start = self._scale_start * s_factor
scale_stop = self._scale_stop * s_factor
scale_step = self._scale_step * s_factor
+ self.scale = s_factor
max_match = []
# check for normalized image
if numpy.amax(scene) <= 1.0:
scene = (scene * 255.0).astype(numpy.uint8)
- if len(scene.shape) == 2:
- scene_gray = scene.copy()
- elif len(scene.shape) == 3:
- if scene.shape[2] == 1:
- scene_gray = scene[:, :, 0]
- else:
- scene_gray = cv2.cvtColor(scene.copy(), cv2.COLOR_RGB2GRAY)
+ scene_gray = gray_scale_img(scene)
print 'Finding chart in scene...'
for scale in numpy.arange(scale_start, scale_stop, scale_step):
scene_scaled = scale_img(scene_gray, scale)
@@ -142,26 +162,36 @@
# determine if optimization results are valid
opt_values = [x[0] for x in max_match]
if 2.0*min(opt_values) > max(opt_values):
- estring = ('Unable to find chart in scene!\n'
+ estring = ('Warning: unable to find chart in scene!\n'
'Check camera distance and self-reported '
'pixel pitch, focal length and hyperfocal distance.')
- raise its.error.Error(estring)
- # find max and draw bbox
- match_index = max_match.index(max(max_match, key=lambda x: x[0]))
- scale = scale_start + scale_step * match_index
- print 'Optimum scale factor: %.3f' % scale
- top_left_scaled = max_match[match_index][1]
- h, w = chart.shape
- bottom_right_scaled = (top_left_scaled[0] + w, top_left_scaled[1] + h)
- top_left = (int(top_left_scaled[0]/scale),
- int(top_left_scaled[1]/scale))
- bottom_right = (int(bottom_right_scaled[0]/scale),
- int(bottom_right_scaled[1]/scale))
- wnorm = float((bottom_right[0]) - top_left[0]) / scene.shape[1]
- hnorm = float((bottom_right[1]) - top_left[1]) / scene.shape[0]
- xnorm = float(top_left[0]) / scene.shape[1]
- ynorm = float(top_left[1]) / scene.shape[0]
- return xnorm, ynorm, wnorm, hnorm
+ print estring
+ self.wnorm = 1.0
+ self.hnorm = 1.0
+ self.xnorm = 0.0
+ self.ynorm = 0.0
+ else:
+ if (max(opt_values) == opt_values[0] or
+ max(opt_values) == opt_values[len(opt_values)-1]):
+ estring = ('Warning: chart is at extreme range of locator '
+ 'check.\n')
+ print estring
+ # find max and draw bbox
+ match_index = max_match.index(max(max_match, key=lambda x: x[0]))
+ self.scale = scale_start + scale_step * match_index
+ print 'Optimum scale factor: %.3f' % self.scale
+ top_left_scaled = max_match[match_index][1]
+ h, w = chart.shape
+ bottom_right_scaled = (top_left_scaled[0] + w,
+ top_left_scaled[1] + h)
+ top_left = (int(top_left_scaled[0]/self.scale),
+ int(top_left_scaled[1]/self.scale))
+ bottom_right = (int(bottom_right_scaled[0]/self.scale),
+ int(bottom_right_scaled[1]/self.scale))
+ self.wnorm = float((bottom_right[0]) - top_left[0]) / scene.shape[1]
+ self.hnorm = float((bottom_right[1]) - top_left[1]) / scene.shape[0]
+ self.xnorm = float(top_left[0]) / scene.shape[1]
+ self.ynorm = float(top_left[1]) / scene.shape[0]
class __UnitTest(unittest.TestCase):
@@ -186,7 +216,8 @@
blur = cv2.blur(chart, (j, j))
blur = blur[:, :, numpy.newaxis]
sharpness[j] = (yuv_full_scale *
- its.image.compute_image_sharpness(blur / white_level))
+ its.image.compute_image_sharpness(blur /
+ white_level))
self.assertTrue(numpy.isclose(sharpness[2]/sharpness[4],
numpy.sqrt(2), atol=0.1))
self.assertTrue(numpy.isclose(sharpness[4]/sharpness[8],
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index d47a995..d4f51f6 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -626,7 +626,10 @@
ytile = math.ceil(ynorm * hfull)
wtile = math.floor(wnorm * wfull)
htile = math.floor(hnorm * hfull)
- return img[ytile:ytile+htile,xtile:xtile+wtile,:].copy()
+ if len(img.shape)==2:
+ return img[ytile:ytile+htile,xtile:xtile+wtile].copy()
+ else:
+ return img[ytile:ytile+htile,xtile:xtile+wtile,:].copy()
def compute_image_means(img):
"""Calculate the mean of each color channel in the image.
@@ -755,6 +758,7 @@
[gy, gx] = numpy.gradient(luma)
return numpy.average(numpy.sqrt(gy*gy + gx*gx))
+
def normalize_img(img):
"""Normalize the image values to between 0 and 1.
@@ -765,21 +769,39 @@
"""
return (img - numpy.amin(img))/(numpy.amax(img) - numpy.amin(img))
-def flip_mirror_img_per_argv(img):
- """Flip/mirror an image if "flip" or "mirror" is in argv
+
+def chart_located_per_argv():
+ """Determine if chart already located outside of test.
+
+ If chart info provided, return location and size. If not, return None.
+
+ Args:
+ None
+ Returns:
+ chart_loc: float converted xnorm,ynorm,wnorm,hnorm,scale from argv text.
+ argv is of form 'chart_loc=0.45,0.45,0.1,0.1,1.0'
+ """
+ for s in sys.argv[1:]:
+ if s[:10] == "chart_loc=" and len(s) > 10:
+ chart_loc = s[10:].split(",")
+ return map(float, chart_loc)
+ return None, None, None, None, None
+
+
+def rotate_img_per_argv(img):
+ """Rotate an image 180 degrees if "rotate" is in argv
Args:
img: 2-D numpy array of image values
Returns:
- Flip/mirrored image
+ Rotated image
"""
img_out = img
- if "flip" in sys.argv:
- img_out = numpy.flipud(img_out)
- if "mirror" in sys.argv:
- img_out = numpy.fliplr(img_out)
+ if "rotate180" in sys.argv:
+ img_out = numpy.fliplr(numpy.flipud(img_out))
return img_out
+
def stationary_lens_cap(cam, req, fmt):
"""Take up to NUM_TRYS caps and save the 1st one with lens stationary.
@@ -804,6 +826,7 @@
raise its.error.Error('Cannot settle lens after %d trys!' % trys)
return cap[NUM_FRAMES-1]
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
diff --git a/apps/CameraITS/tests/scene2/test_faces.py b/apps/CameraITS/tests/scene2/test_faces.py
index 4e30fc1..2acce85 100644
--- a/apps/CameraITS/tests/scene2/test_faces.py
+++ b/apps/CameraITS/tests/scene2/test_faces.py
@@ -60,7 +60,7 @@
# but it should detect at least one face in last frame
if i == NUM_TEST_FRAMES - 1:
img = its.image.convert_capture_to_rgb_image(cap, props=props)
- img = its.image.flip_mirror_img_per_argv(img)
+ img = its.image.rotate_img_per_argv(img)
img_name = "%s_fd_mode_%s.jpg" % (NAME, fd_mode)
its.image.write_image(img, img_name)
if len(faces) == 0:
diff --git a/apps/CameraITS/tests/scene3/test_flip_mirror.py b/apps/CameraITS/tests/scene3/test_flip_mirror.py
new file mode 100644
index 0000000..86d96f1
--- /dev/null
+++ b/apps/CameraITS/tests/scene3/test_flip_mirror.py
@@ -0,0 +1,130 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import cv2
+
+import its.caps
+import its.cv2image
+import its.device
+import its.image
+import its.objects
+import numpy as np
+
+NAME = os.path.basename(__file__).split('.')[0]
+CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+ 'test_images', 'ISO12233.png')
+CHART_HEIGHT = 13.5 # cm
+CHART_DISTANCE = 30.0 # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
+CHART_ORIENTATIONS = ['nominal', 'flip', 'mirror', 'rotate']
+VGA_WIDTH = 640
+VGA_HEIGHT = 480
+(X_CROP, Y_CROP) = (0.5, 0.5) # crop center area of ISO12233 chart
+
+
+def test_flip_mirror(cam, props, fmt, chart):
+ """Return if image is flipped or mirrored.
+
+ Args:
+ cam (class): An open device session
+ props (class): Properties of cam
+ fmt (dict): Capture format
+ chart (class): Object with chart properties
+
+ Returns:
+ boolean: True if flipped, False if not
+ """
+
+ # determine if in debug mode
+ debug = its.caps.debug_mode()
+
+ # get a local copy of the chart template
+ template = cv2.imread(CHART_FILE, cv2.IMREAD_ANYDEPTH)
+
+ # take img, crop chart, scale and prep for cv2 template match
+ req = its.objects.auto_capture_request()
+ cap = cam.do_capture(req, fmt)
+ y, _, _ = its.image.convert_capture_to_planes(cap, props)
+ y = its.image.rotate_img_per_argv(y)
+ patch = its.image.get_image_patch(y, chart.xnorm, chart.ynorm,
+ chart.wnorm, chart.hnorm)
+ patch = 255 * its.cv2image.gray_scale_img(patch)
+ patch = its.cv2image.scale_img(patch.astype(np.uint8), chart.scale)
+
+ # save full images if in debug
+ if debug:
+ its.image.write_image(template[:, :, np.newaxis]/255.0,
+ '%s_template.jpg' % NAME)
+
+ # save patch
+ its.image.write_image(patch[:, :, np.newaxis]/255.0,
+ '%s_scene_patch.jpg' % NAME)
+
+ # crop center areas and strip off any extra rows/columns
+ template = its.image.get_image_patch(template, (1-X_CROP)/2, (1-Y_CROP)/2,
+ X_CROP, Y_CROP)
+ patch = its.image.get_image_patch(patch, (1-X_CROP)/2,
+ (1-Y_CROP)/2, X_CROP, Y_CROP)
+ patch = patch[0:min(patch.shape[0], template.shape[0]),
+ 0:min(patch.shape[1], template.shape[1])]
+ comp_chart = patch
+
+ # determine optimum orientation
+ opts = []
+ for orientation in CHART_ORIENTATIONS:
+ if orientation == 'flip':
+ comp_chart = np.flipud(patch)
+ elif orientation == 'mirror':
+ comp_chart = np.fliplr(patch)
+ elif orientation == 'rotate':
+ comp_chart = np.flipud(np.fliplr(patch))
+ correlation = cv2.matchTemplate(comp_chart, template, cv2.TM_CCOEFF)
+ _, opt_val, _, _ = cv2.minMaxLoc(correlation)
+ if debug:
+ cv2.imwrite('%s_%s.jpg' % (NAME, orientation), comp_chart)
+ print ' %s correlation value: %d' % (orientation, opt_val)
+ opts.append(opt_val)
+
+ # determine if 'nominal' or 'rotated' is best orientation
+ assert_flag = (opts[0] == max(opts) or opts[3] == max(opts))
+ assert assert_flag, ('Optimum orientation is %s' %
+ CHART_ORIENTATIONS[np.argmax(opts)])
+ # print warning if rotated
+ if opts[3] == max(opts):
+ print 'Image is rotated 180 degrees. Try "rotate" flag.'
+
+
+def main():
+ """Test if image is properly oriented."""
+
+ print '\nStarting test_flip_mirror.py'
+
+ # initialize chart class and locate chart in scene
+ chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+ CHART_SCALE_START, CHART_SCALE_STOP,
+ CHART_SCALE_STEP)
+
+ with its.device.ItsSession() as cam:
+ props = cam.get_camera_properties()
+ fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
+
+ # test that image is not flipped, mirrored, or rotated
+ test_flip_mirror(cam, props, fmt, chart)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
index cd563be..24c6841 100644
--- a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
+++ b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
@@ -37,19 +37,20 @@
CHART_SCALE_STEP = 0.025
-def test_lens_movement_reporting(cam, props, fmt, sensitivity, exp, af_fd):
+def test_lens_movement_reporting(cam, props, fmt, gain, exp, af_fd, chart):
"""Return fd, sharpness, lens state of the output images.
Args:
cam: An open device session.
props: Properties of cam
fmt: dict; capture format
- sensitivity: Sensitivity for the 3A request as defined in
+ gain: Sensitivity for the 3A request as defined in
android.sensor.sensitivity
exp: Exposure time for the 3A request as defined in
android.sensor.exposureTime
af_fd: Focus distance for the 3A request as defined in
android.lens.focusDistance
+ chart: Object that contains chart information
Returns:
Object containing reported sharpness of the output image, keyed by
@@ -57,15 +58,6 @@
'sharpness'
"""
- # initialize chart class
- chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
- CHART_SCALE_START, CHART_SCALE_STOP,
- CHART_SCALE_STEP)
-
- # find chart location
- xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
- exp, af_fd)
-
# initialize variables and take data sets
data_set = {}
white_level = int(props['android.sensor.info.whiteLevel'])
@@ -74,7 +66,7 @@
fds = sorted(fds * NUM_IMGS)
reqs = []
for i, fd in enumerate(fds):
- reqs.append(its.objects.manual_capture_request(sensitivity, exp))
+ reqs.append(its.objects.manual_capture_request(gain, exp))
reqs[i]['android.lens.focusDistance'] = fd
caps = cam.do_capture(reqs, fmt)
for i, cap in enumerate(caps):
@@ -92,12 +84,12 @@
print ' current lens location (diopters): %.3f' % data['loc']
print ' lens moving %r' % data['lens_moving']
y, _, _ = its.image.convert_capture_to_planes(cap, props)
- y = its.image.flip_mirror_img_per_argv(y)
- chart = its.image.normalize_img(its.image.get_image_patch(y,
- xnorm, ynorm,
- wnorm, hnorm))
- its.image.write_image(chart, '%s_i=%d_chart.jpg' % (NAME, i))
- data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+ y = its.image.rotate_img_per_argv(y)
+ chart.img = its.image.normalize_img(its.image.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ its.image.write_image(chart.img, '%s_i=%d_chart.jpg' % (NAME, i))
+ data['sharpness'] = white_level*its.image.compute_image_sharpness(
+ chart.img)
print 'Chart sharpness: %.1f\n' % data['sharpness']
data_set[i] = data
return data_set
@@ -110,6 +102,11 @@
"""
print '\nStarting test_lens_movement_reporting.py'
+ # initialize chart class
+ chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+ CHART_SCALE_START, CHART_SCALE_STOP,
+ CHART_SCALE_STEP)
+
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
its.caps.skip_unless(not its.caps.fixed_focus(props))
@@ -121,7 +118,7 @@
s, e, _, _, fd = cam.do_3a(get_results=True)
# Get sharpness for each focal distance
- d = test_lens_movement_reporting(cam, props, fmt, s, e, fd)
+ d = test_lens_movement_reporting(cam, props, fmt, s, e, fd, chart)
for k in sorted(d):
print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
'sharpness: %.1f \tlens_moving: %r \t'
diff --git a/apps/CameraITS/tests/scene3/test_lens_position.py b/apps/CameraITS/tests/scene3/test_lens_position.py
index f850e3d..2194b8c 100644
--- a/apps/CameraITS/tests/scene3/test_lens_position.py
+++ b/apps/CameraITS/tests/scene3/test_lens_position.py
@@ -38,7 +38,7 @@
CHART_SCALE_STEP = 0.025
-def test_lens_position(cam, props, fmt, sensitivity, exp, af_fd):
+def test_lens_position(cam, props, fmt, sensitivity, exp, chart):
"""Return fd, sharpness, lens state of the output images.
Args:
@@ -49,8 +49,7 @@
android.sensor.sensitivity
exp: Exposure time for the 3A request as defined in
android.sensor.exposureTime
- af_fd: Focus distance for the 3A request as defined in
- android.lens.focusDistance
+ chart: Object with chart properties
Returns:
Dictionary of results for different focal distance captures
@@ -58,15 +57,6 @@
d_static, d_moving
"""
- # initialize chart class
- chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
- CHART_SCALE_START, CHART_SCALE_STOP,
- CHART_SCALE_STEP)
-
- # find chart location
- xnorm, ynorm, wnorm, hnorm = chart.locate(cam, props, fmt, sensitivity,
- exp, af_fd)
-
# initialize variables and take data sets
data_static = {}
data_moving = {}
@@ -89,11 +79,11 @@
print ' focus distance (diopters): %.3f' % data['fd']
print ' current lens location (diopters): %.3f' % data['loc']
y, _, _ = its.image.convert_capture_to_planes(cap, props)
- chart = its.image.normalize_img(its.image.get_image_patch(y,
- xnorm, ynorm,
- wnorm, hnorm))
- its.image.write_image(chart, '%s_stat_i=%d_chart.jpg' % (NAME, i))
- data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+ chart.img = its.image.normalize_img(its.image.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ its.image.write_image(chart.img, '%s_stat_i=%d_chart.jpg' % (NAME, i))
+ data['sharpness'] = white_level*its.image.compute_image_sharpness(
+ chart.img)
print 'Chart sharpness: %.1f\n' % data['sharpness']
data_static[i] = data
# take moving data set
@@ -115,12 +105,12 @@
print ' focus distance (diopters): %.3f' % data['fd']
print ' current lens location (diopters): %.3f' % data['loc']
y, _, _ = its.image.convert_capture_to_planes(cap, props)
- y = its.image.flip_mirror_img_per_argv(y)
- chart = its.image.normalize_img(its.image.get_image_patch(y,
- xnorm, ynorm,
- wnorm, hnorm))
- its.image.write_image(chart, '%s_move_i=%d_chart.jpg' % (NAME, i))
- data['sharpness'] = white_level*its.image.compute_image_sharpness(chart)
+ y = its.image.rotate_img_per_argv(y)
+ chart.img = its.image.normalize_img(its.image.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ its.image.write_image(chart.img, '%s_move_i=%d_chart.jpg' % (NAME, i))
+ data['sharpness'] = white_level*its.image.compute_image_sharpness(
+ chart.img)
print 'Chart sharpness: %.1f\n' % data['sharpness']
data_moving[i] = data
return data_static, data_moving
@@ -128,19 +118,23 @@
def main():
"""Test if focus position is properly reported for moving lenses."""
-
print '\nStarting test_lens_position.py'
+ # initialize chart class
+ chart = its.cv2image.Chart(CHART_FILE, CHART_HEIGHT, CHART_DISTANCE,
+ CHART_SCALE_START, CHART_SCALE_STOP,
+ CHART_SCALE_STEP)
+
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
its.caps.skip_unless(not its.caps.fixed_focus(props))
its.caps.skip_unless(its.caps.lens_calibrated(props))
fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
- # Get proper sensitivity, exposure time, and focus distance with 3A.
- s, e, _, _, fd = cam.do_3a(get_results=True)
+ # Get proper sensitivity and exposure time with 3A
+ s, e, _, _, _ = cam.do_3a(get_results=True)
# Get sharpness for each focal distance
- d_stat, d_move = test_lens_position(cam, props, fmt, s, e, fd)
+ d_stat, d_move = test_lens_position(cam, props, fmt, s, e, chart)
print 'Lens stationary'
for k in sorted(d_stat):
print ('i: %d\tfd: %.3f\tlens location (diopters): %.3f \t'
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index e8a5b81..faacaf9 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -116,7 +116,7 @@
# Split by comma and convert each dimension to int.
[w, h] = map(int, s[9:].split(","))
elif s[:12] == "test_length=" and len(s) > 12:
- test_length = int(s[12:])
+ test_length = float(s[12:])
# Collect or load the camera+gyro data. All gyro events as well as camera
# timestamps are in the "events" dictionary, and "frames" is a list of
@@ -345,7 +345,7 @@
if num_features < MIN_FEATURE_PTS:
print "Not enough feature points in frame", i
print "Need at least %d features, got %d" % (
- MIN_FEATURE_PTS, num_features)
+ MIN_FEATURE_PTS, num_features)
assert 0
else:
print "Number of features in frame %d is %d" % (i, num_features)
@@ -447,13 +447,12 @@
fmt = {"format": "yuv", "width": w, "height": h}
s, e, _, _, _ = cam.do_3a(get_results=True, do_af=False)
req = its.objects.manual_capture_request(s, e)
- fps = 30
req["android.lens.focusDistance"] = 1 / (CHART_DISTANCE * CM_TO_M)
req["android.control.aeTargetFpsRange"] = [fps, fps]
req["android.sensor.frameDuration"] = int(1000.0/fps * MSEC_TO_NSEC)
- print "Capturing %dx%d with sens. %d, exp. time %.1fms" % (
- w, h, s, e*NSEC_TO_MSEC)
- caps = cam.do_capture([req]*fps*test_length, fmt)
+ print "Capturing %dx%d with sens. %d, exp. time %.1fms at %dfps" % (
+ w, h, s, e*NSEC_TO_MSEC, fps)
+ caps = cam.do_capture([req]*int(fps*test_length), fmt)
# Get the gyro events.
print "Reading out sensor events"
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index a6fc759..15dd837 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -21,13 +21,24 @@
import sys
import its.caps
+import its.cv2image
import its.device
+import its.image
from its.device import ItsSession
CHART_DELAY = 1 # seconds
+CHART_DISTANCE = 30.0 # cm
+CHART_HEIGHT = 13.5 # cm
+CHART_SCALE_START = 0.65
+CHART_SCALE_STOP = 1.35
+CHART_SCALE_STEP = 0.025
FACING_EXTERNAL = 2
NUM_TRYS = 2
+SCENE3_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
+ 'test_images', 'ISO12233.png')
SKIP_RET_CODE = 101 # note this must be same as tests/scene*/test_*
+VGA_HEIGHT = 480
+VGA_WIDTH = 640
def evaluate_socket_failure(err_file_path):
@@ -98,6 +109,7 @@
],
"scene3": [
"test_3a_consistency",
+ "test_flip_mirror",
"test_lens_movement_reporting",
"test_lens_position"
],
@@ -294,6 +306,15 @@
valid_scene_code = subprocess.call(cmd, cwd=topdir)
assert valid_scene_code == 0
print "Start running ITS on camera %s, %s" % (camera_id, scene)
+ # Extract chart from scene for scene3 once up front
+ chart_loc_arg = ''
+ if scene == 'scene3':
+ chart = its.cv2image.Chart(SCENE3_FILE, CHART_HEIGHT,
+ CHART_DISTANCE, CHART_SCALE_START,
+ CHART_SCALE_STOP, CHART_SCALE_STEP)
+ chart_loc_arg = 'chart_loc=%.2f,%.2f,%.2f,%.2f,%.3f' % (
+ chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm,
+ chart.scale)
# Run each test, capturing stdout and stderr.
for (testname, testpath) in tests:
if auto_scene_switch:
@@ -325,7 +346,7 @@
test_code = skip_code
if skip_code is not SKIP_RET_CODE:
cmd = ['python', os.path.join(os.getcwd(), testpath)]
- cmd += sys.argv[1:] + [camera_id_arg]
+ cmd += sys.argv[1:] + [camera_id_arg] + [chart_loc_arg]
with open(outpath, 'w') as fout, open(errpath, 'w') as ferr:
test_code = subprocess.call(
cmd, stderr=ferr, stdout=fout, cwd=outdir)
diff --git a/apps/CameraITS/tools/run_sensor_fusion_box.py b/apps/CameraITS/tools/run_sensor_fusion_box.py
index ec16b3d..650a1f6 100644
--- a/apps/CameraITS/tools/run_sensor_fusion_box.py
+++ b/apps/CameraITS/tools/run_sensor_fusion_box.py
@@ -104,6 +104,7 @@
fps_arg = 'fps=' + fps
test_length_arg = 'test_length=' + test_length
+ print 'Capturing at %sfps' % fps
os.mkdir(os.path.join(tmpdir, camera_id))
diff --git a/apps/CtsVerifier/res/values-watch/strings.xml b/apps/CtsVerifier/res/values-watch/strings.xml
index 6f1470c..37ad24f 100644
--- a/apps/CtsVerifier/res/values-watch/strings.xml
+++ b/apps/CtsVerifier/res/values-watch/strings.xml
@@ -24,4 +24,14 @@
perform a palm press to turn off display and put device into suspend mode. The screen will
turn on and device will vibrate once all the tests are completed.
</string>
+
+ <string name="da_tapjacking_instructions">
+ 1. Launch the device admin add screen by pressing the button below.\n
+ 2. Wait for an overlaying transparent activity to show up obscuring the device admin details window.\n
+ 3. The button to activate the admin should be disabled and should not register any taps.\n
+ 4. Wait 10 seconds for the overlaying transparent activity to go away.\n
+ 5. Exit the device admin details and return to this screen.\n
+ Pass the test if the device admin could not be activated while the details
+ window was being obscured.
+ </string>
</resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
index 52c7ed5..e81f301 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/tapjacking/OverlayingActivity.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import android.app.Activity;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.WindowManager;
@@ -30,6 +31,8 @@
public class OverlayingActivity extends Activity {
+ private static final long ACTIVITY_TIMEOUT_ON_WATCH = 10_000;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -37,5 +40,9 @@
WindowManager.LayoutParams params = getWindow().getAttributes();
params.flags = FLAG_LAYOUT_NO_LIMITS | FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE
| FLAG_KEEP_SCREEN_ON;
+ if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ getWindow().getDecorView().postDelayed(() -> OverlayingActivity.this.finish(),
+ ACTIVITY_TIMEOUT_ON_WATCH);
+ }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index a4adfda..a960c67 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -261,19 +261,18 @@
new ButtonInfo(R.string.enterprise_privacy_finish,
buildCommandIntent(
CommandReceiverActivity.COMMAND_REMOVE_MANAGED_PROFILE))}));
- // Disabled for API 26 due to b/63696536.
- // adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE,
- // R.string.enterprise_privacy_failed_password_wipe,
- // R.string.enterprise_privacy_failed_password_wipe_info,
- // new ButtonInfo[] {
- // new ButtonInfo(R.string.enterprise_privacy_open_settings,
- // new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
- // new ButtonInfo(R.string.enterprise_privacy_set_limit,
- // buildCommandIntent(CommandReceiverActivity
- // .COMMAND_SET_MAXIMUM_PASSWORD_ATTEMPTS)),
- // new ButtonInfo(R.string.enterprise_privacy_finish,
- // buildCommandIntent(CommandReceiverActivity
- // .COMMAND_CLEAR_MAXIMUM_PASSWORD_ATTEMPTS))}));
+ adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_FAILED_PASSWORD_WIPE,
+ R.string.enterprise_privacy_failed_password_wipe,
+ R.string.enterprise_privacy_failed_password_wipe_info,
+ new ButtonInfo[] {
+ new ButtonInfo(R.string.enterprise_privacy_open_settings,
+ new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
+ new ButtonInfo(R.string.enterprise_privacy_set_limit,
+ buildCommandIntent(CommandReceiverActivity
+ .COMMAND_SET_MAXIMUM_PASSWORD_ATTEMPTS)),
+ new ButtonInfo(R.string.enterprise_privacy_finish,
+ buildCommandIntent(CommandReceiverActivity
+ .COMMAND_CLEAR_MAXIMUM_PASSWORD_ATTEMPTS))}));
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
adapter.add(createInteractiveTestItem(this,
ENTERPRISE_PRIVACY_COMP_FAILED_PASSWORD_WIPE,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
index 7cfa040..b8cb0e8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
@@ -356,7 +356,7 @@
Log.e(TAG, "failed to unpack data from mocklistener", e);
}
}
- pass &= found.size() == 3;
+ pass &= found.size() >= 3;
status = pass ? PASS : FAIL;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 9f8438e..9aaf519 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -265,9 +265,6 @@
"data integrity test: notification ID (%d, %d)");
pass &= checkEquals(mWhen3, payload.getLong(JSON_WHEN),
"data integrity test: notification when (%d, %d)");
- } else {
- pass = false;
- logFail("unexpected notification tag: " + tag);
}
} catch (JSONException e) {
pass = false;
@@ -275,7 +272,7 @@
}
}
- pass &= found.size() == 3;
+ pass &= found.size() >= 3;
status = pass ? PASS : FAIL;
}
diff --git a/apps/PermissionApp/AndroidManifest.xml b/apps/PermissionApp/AndroidManifest.xml
index 82e3617..f880933 100644
--- a/apps/PermissionApp/AndroidManifest.xml
+++ b/apps/PermissionApp/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-sdk android:minSdkVersion="23"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<application android:label="CtsPermissionApp"
android:icon="@drawable/ic_permissionapp">
diff --git a/common/device-side/nativetesthelper/Android.mk b/common/device-side/nativetesthelper/Android.mk
new file mode 100644
index 0000000..19f584d
--- /dev/null
+++ b/common/device-side/nativetesthelper/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-devicesidelib
+LOCAL_MODULE := nativetesthelper
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/device-side/nativetesthelper/jni/Android.mk b/common/device-side/nativetesthelper/jni/Android.mk
new file mode 100644
index 0000000..f970e8c
--- /dev/null
+++ b/common/device-side/nativetesthelper/jni/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libnativetesthelper_jni
+
+LOCAL_SRC_FILES := \
+ gtest_wrapper.cpp
+
+LOCAL_SHARED_LIBRARIES := libnativehelper_compat_libc++
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_ndk_c++
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libgtest_ndk_c++
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_MULTILIB := both
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp b/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp
new file mode 100644
index 0000000..1f91b3a
--- /dev/null
+++ b/common/device-side/nativetesthelper/jni/gtest_wrapper.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <gtest/gtest.h>
+
+static struct {
+ jclass clazz;
+
+ /** static methods **/
+ jmethodID createTestDescription;
+
+ /** methods **/
+ jmethodID addChild;
+} gDescription;
+
+static struct {
+ jclass clazz;
+
+ jmethodID fireTestStarted;
+ jmethodID fireTestIgnored;
+ jmethodID fireTestFailure;
+ jmethodID fireTestFinished;
+
+} gRunNotifier;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gAssertionFailure;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gFailure;
+
+jobject gEmptyAnnotationsArray;
+
+static jobject createTestDescription(JNIEnv* env, const char* className, const char* testName) {
+ ScopedLocalRef<jstring> jClassName(env, env->NewStringUTF(className));
+ ScopedLocalRef<jstring> jTestName(env, env->NewStringUTF(testName));
+ return env->CallStaticObjectMethod(gDescription.clazz, gDescription.createTestDescription,
+ jClassName.get(), jTestName.get(), gEmptyAnnotationsArray);
+}
+
+static void addChild(JNIEnv* env, jobject description, jobject childDescription) {
+ env->CallVoidMethod(description, gDescription.addChild, childDescription);
+}
+
+
+class JUnitNotifyingListener : public ::testing::EmptyTestEventListener {
+public:
+
+ JUnitNotifyingListener(JNIEnv* env, jobject runNotifier)
+ : mEnv(env)
+ , mRunNotifier(runNotifier)
+ , mCurrentTestDescription{env, nullptr}
+ {}
+ virtual ~JUnitNotifyingListener() {}
+
+ virtual void OnTestStart(const testing::TestInfo &testInfo) override {
+ mCurrentTestDescription.reset(
+ createTestDescription(mEnv, testInfo.test_case_name(), testInfo.name()));
+ notify(gRunNotifier.fireTestStarted);
+ }
+
+ virtual void OnTestPartResult(const testing::TestPartResult &testPartResult) override {
+ if (!testPartResult.passed()) {
+ char message[1024];
+ snprintf(message, 1024, "%s:%d\n%s", testPartResult.file_name(), testPartResult.line_number(),
+ testPartResult.message());
+ ScopedLocalRef<jstring> jmessage(mEnv, mEnv->NewStringUTF(message));
+ ScopedLocalRef<jobject> jthrowable(mEnv, mEnv->NewObject(gAssertionFailure.clazz,
+ gAssertionFailure.ctor, jmessage.get()));
+ ScopedLocalRef<jobject> jfailure(mEnv, mEnv->NewObject(gFailure.clazz,
+ gFailure.ctor, mCurrentTestDescription.get(), jthrowable.get()));
+ mEnv->CallVoidMethod(mRunNotifier, gRunNotifier.fireTestFailure, jfailure.get());
+ }
+ }
+
+ virtual void OnTestEnd(const testing::TestInfo&) override {
+ notify(gRunNotifier.fireTestFinished);
+ mCurrentTestDescription.reset();
+ }
+
+ virtual void OnTestProgramEnd(const testing::UnitTest& unitTest) override {
+ // Invoke the notifiers for all the disabled tests
+ for (int testCaseIndex = 0; testCaseIndex < unitTest.total_test_case_count(); testCaseIndex++) {
+ auto testCase = unitTest.GetTestCase(testCaseIndex);
+ for (int testIndex = 0; testIndex < testCase->total_test_count(); testIndex++) {
+ auto testInfo = testCase->GetTestInfo(testIndex);
+ if (!testInfo->should_run()) {
+ mCurrentTestDescription.reset(
+ createTestDescription(mEnv, testCase->name(), testInfo->name()));
+ notify(gRunNotifier.fireTestIgnored);
+ mCurrentTestDescription.reset();
+ }
+ }
+ }
+ }
+
+private:
+ void notify(jmethodID method) {
+ mEnv->CallVoidMethod(mRunNotifier, method, mCurrentTestDescription.get());
+ }
+
+ JNIEnv* mEnv;
+ jobject mRunNotifier;
+ ScopedLocalRef<jobject> mCurrentTestDescription;
+};
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_android_gtestrunner_GtestRunner_nInitialize(JNIEnv *env, jclass, jobject suite) {
+ // Initialize gtest, removing the default result printer
+ int argc = 1;
+ const char* argv[] = { "gtest_wrapper" };
+ ::testing::InitGoogleTest(&argc, (char**) argv);
+
+ auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+
+ gDescription.clazz = (jclass) env->NewGlobalRef(env->FindClass("org/junit/runner/Description"));
+ gDescription.createTestDescription = env->GetStaticMethodID(gDescription.clazz, "createTestDescription",
+ "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/annotation/Annotation;)Lorg/junit/runner/Description;");
+ gDescription.addChild = env->GetMethodID(gDescription.clazz, "addChild",
+ "(Lorg/junit/runner/Description;)V");
+
+ jclass annotations = env->FindClass("java/lang/annotation/Annotation");
+ gEmptyAnnotationsArray = env->NewGlobalRef(env->NewObjectArray(0, annotations, nullptr));
+
+ gAssertionFailure.clazz = (jclass) env->NewGlobalRef(env->FindClass("java/lang/AssertionError"));
+ gAssertionFailure.ctor = env->GetMethodID(gAssertionFailure.clazz, "<init>", "(Ljava/lang/Object;)V");
+
+ gFailure.clazz = (jclass) env->NewGlobalRef(env->FindClass("org/junit/runner/notification/Failure"));
+ gFailure.ctor = env->GetMethodID(gFailure.clazz, "<init>",
+ "(Lorg/junit/runner/Description;Ljava/lang/Throwable;)V");
+
+ gRunNotifier.clazz = (jclass) env->NewGlobalRef(
+ env->FindClass("org/junit/runner/notification/RunNotifier"));
+ gRunNotifier.fireTestStarted = env->GetMethodID(gRunNotifier.clazz, "fireTestStarted",
+ "(Lorg/junit/runner/Description;)V");
+ gRunNotifier.fireTestIgnored = env->GetMethodID(gRunNotifier.clazz, "fireTestIgnored",
+ "(Lorg/junit/runner/Description;)V");
+ gRunNotifier.fireTestFinished = env->GetMethodID(gRunNotifier.clazz, "fireTestFinished",
+ "(Lorg/junit/runner/Description;)V");
+ gRunNotifier.fireTestFailure = env->GetMethodID(gRunNotifier.clazz, "fireTestFailure",
+ "(Lorg/junit/runner/notification/Failure;)V");
+
+ auto unitTest = ::testing::UnitTest::GetInstance();
+ for (int testCaseIndex = 0; testCaseIndex < unitTest->total_test_case_count(); testCaseIndex++) {
+ auto testCase = unitTest->GetTestCase(testCaseIndex);
+ for (int testIndex = 0; testIndex < testCase->total_test_count(); testIndex++) {
+ auto testInfo = testCase->GetTestInfo(testIndex);
+ ScopedLocalRef<jobject> testDescription(env,
+ createTestDescription(env, testCase->name(), testInfo->name()));
+ addChild(env, suite, testDescription.get());
+ }
+ }
+}
+
+extern "C"
+JNIEXPORT jboolean JNICALL
+Java_com_android_gtestrunner_GtestRunner_nRun(JNIEnv *env, jclass, jobject notifier) {
+ auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
+ JUnitNotifyingListener junitListener{env, notifier};
+ listeners.Append(&junitListener);
+ int success = RUN_ALL_TESTS();
+ listeners.Release(&junitListener);
+ return success == 0;
+}
diff --git a/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java b/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java
new file mode 100644
index 0000000..222a1a0
--- /dev/null
+++ b/common/device-side/nativetesthelper/src/com/android/gtestrunner/GtestRunner.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gtestrunner;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+public class GtestRunner extends Runner {
+ private static boolean sOnceFlag = false;
+
+ private Class mTargetClass;
+ private Description mDescription;
+
+ public GtestRunner(Class testClass) {
+ synchronized (GtestRunner.class) {
+ if (sOnceFlag) {
+ throw new IllegalStateException("Error multiple GtestRunners defined");
+ }
+ sOnceFlag = true;
+ }
+
+ mTargetClass = testClass;
+ TargetLibrary library = (TargetLibrary) testClass.getAnnotation(TargetLibrary.class);
+ if (library == null) {
+ throw new IllegalStateException("Missing required @TargetLibrary annotation");
+ }
+ System.loadLibrary(library.value());
+ mDescription = Description.createSuiteDescription(testClass);
+ nInitialize(mDescription);
+ }
+
+ @Override
+ public Description getDescription() {
+ return mDescription;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ nRun(notifier);
+ }
+
+ private static native void nInitialize(Description description);
+ private static native void nRun(RunNotifier notifier);
+}
diff --git a/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java b/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java
new file mode 100644
index 0000000..23bc53d
--- /dev/null
+++ b/common/device-side/nativetesthelper/src/com/android/gtestrunner/TargetLibrary.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gtestrunner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface TargetLibrary {
+ String value();
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 743f816..f52101b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -62,6 +62,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@@ -82,6 +84,7 @@
private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
private static final String CTS_PREFIX = "cts:";
private static final String BUILD_INFO = CTS_PREFIX + "build_";
+ private static final String LATEST_LINK_NAME = "latest";
private static final List<String> NOT_RETRY_FILES = Arrays.asList(
ChecksumReporter.NAME,
@@ -518,6 +521,16 @@
info("Test Logs: %s", mLogDir.getCanonicalPath());
debug("Full Result: %s", zippedResults.getCanonicalPath());
+ Path latestLink = createLatestLinkDirectory(mResultDir.toPath());
+ if (latestLink != null) {
+ info("Latest results link: " + latestLink.toAbsolutePath());
+ }
+
+ latestLink = createLatestLinkDirectory(mLogDir.toPath());
+ if (latestLink != null) {
+ info("Latest logs link: " + latestLink.toAbsolutePath());
+ }
+
saveLog(resultFile, zippedResults);
uploadResult(resultFile);
@@ -534,6 +547,30 @@
moduleProgress);
}
+ private Path createLatestLinkDirectory(Path directory) {
+ Path link = null;
+
+ Path parent = directory.getParent();
+
+ if (parent != null) {
+ link = parent.resolve(LATEST_LINK_NAME);
+ try {
+ // if latest already exists, we have to remove it before creating
+ Files.deleteIfExists(link);
+ Files.createSymbolicLink(link, directory);
+ } catch (IOException ioe) {
+ CLog.e("Exception while attempting to create 'latest' link to: [%s]",
+ directory);
+ CLog.e(ioe);
+ return null;
+ } catch (UnsupportedOperationException uoe) {
+ CLog.e("Failed to create 'latest' symbolic link - unsupported operation");
+ return null;
+ }
+ }
+ return link;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/error_prone_rules_tests.mk b/error_prone_rules_tests.mk
index d17828d..7c729ec 100644
--- a/error_prone_rules_tests.mk
+++ b/error_prone_rules_tests.mk
@@ -17,9 +17,13 @@
# Goal is to eventually merge with error_prone_rules.mk
LOCAL_ERROR_PRONE_FLAGS:= -Xep:ArrayToString:ERROR \
-Xep:CollectionIncompatibleType:ERROR \
+ -Xep:EqualsIncompatibleType:ERROR \
-Xep:EqualsNaN:ERROR \
-Xep:FormatString:ERROR \
+ -Xep:IdentityBinaryExpression:ERROR \
-Xep:JUnit3TestNotRun:ERROR \
+ -Xep:JUnitAmbiguousTestClass:ERROR \
+ -Xep:MissingFail:ERROR \
-Xep:SizeGreaterThanOrEqualsZero:ERROR \
-Xep:TryFailThrowable:ERROR
diff --git a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
index 3f2ffa8..75ffc85 100644
--- a/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
+++ b/hostsidetests/aadb/src/android/aadb/cts/TestDeviceStressTest.java
@@ -33,8 +33,8 @@
*/
public class TestDeviceStressTest extends DeviceTestCase {
- private static final int TEST_FILE_COUNT= 200;
- private int mIterations = 25;
+ private static final int TEST_FILE_COUNT= 100;
+ private int mIterations = 20;
private ITestDevice mTestDevice;
@Override
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
index 1f5d669..591dcb4 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
@@ -274,19 +274,15 @@
executePush(apkFile.getAbsolutePath(), targetPathApk, targetDir);
assertTrue("Failed to push APK from ", doesFileExist(targetPathApk));
// Run profman to create the real profile on device.
- try {
- String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
- pathSpec = pathSpec.replace("package:", "");
- assertTrue("Failed find APK " + pathSpec, doesFileExist(pathSpec));
- executeSuShellAdbCommand(
+ String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
+ pathSpec = pathSpec.replace("package:", "");
+ assertTrue("Failed find APK " + pathSpec, doesFileExist(pathSpec));
+ executeSuShellAdbCommand(
"profman",
"--create-profile-from=" + targetPathTemp,
"--apk=" + pathSpec,
"--dex-location=" + pathSpec,
"--reference-profile-file=" + targetPath);
- } catch (Exception e) {
- assertEquals("", e.toString());
- }
executeSuShellAdbCommand(0, "chown", owner, targetPath);
// Verify that the file was written successfully
assertTrue("failed to create profile file", doesFileExist(targetPath));
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
index bc8d3d3..938ee07 100644
--- a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java
new file mode 100644
index 0000000..d477706
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearApplicationDataTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class that calls DPM.clearApplicationUserData and verifies that it doesn't time out.
+ */
+public class ClearApplicationDataTest extends BaseDeviceAdminTest {
+ private static final String TEST_PKG = "com.android.cts.intent.receiver";
+ private static final Semaphore mSemaphore = new Semaphore(0);
+ private static final long CLEAR_APPLICATION_DATA_TIMEOUT_S = 10;
+
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mHandlerThread = new HandlerThread("ClearApplicationData");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mHandlerThread.quitSafely();
+ super.tearDown();
+ }
+
+ public void testClearApplicationData() throws Exception {
+ mDevicePolicyManager.clearApplicationUserData(ADMIN_RECEIVER_COMPONENT, TEST_PKG,
+ (String pkg, boolean succeeded) -> {
+ assertEquals(TEST_PKG, pkg);
+ assertTrue(succeeded);
+ mSemaphore.release();
+ }, mHandler);
+
+ assertTrue("Clearing application data took too long",
+ mSemaphore.tryAcquire(CLEAR_APPLICATION_DATA_TIMEOUT_S, TimeUnit.SECONDS));
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 6c706ee..70a5d09 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -22,7 +22,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.os.UserManager;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
@@ -47,6 +46,7 @@
private static final String SIMPLE_PRE_M_APP_PACKAGE_NAME =
"com.android.cts.launcherapps.simplepremapp";
private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS";
+ private static final String DEVELOPMENT_PERMISSION = "android.permission.INTERACT_ACROSS_USERS";
private static final String PERMISSIONS_ACTIVITY_NAME
= PERMISSION_APP_PACKAGE_NAME + ".PermissionActivity";
@@ -227,6 +227,15 @@
assertSetPermissionGrantStatePreMApp(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
}
+ public void testPermissionGrantState_developmentPermission() throws Exception {
+ assertFailedToSetDevelopmentPermissionGrantState(
+ DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
+ assertFailedToSetDevelopmentPermissionGrantState(
+ DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+ assertFailedToSetDevelopmentPermissionGrantState(
+ DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ }
+
private void assertPermissionRequest(int expected) throws Exception {
assertPermissionRequest(expected, null);
}
@@ -274,6 +283,18 @@
value);
}
+ private void assertFailedToSetDevelopmentPermissionGrantState(int value) throws Exception {
+ assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+ PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION, value));
+ assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+ PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION),
+ DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+ assertEquals(mPackageManager.checkPermission(DEVELOPMENT_PERMISSION,
+ PERMISSION_APP_PACKAGE_NAME),
+ PackageManager.PERMISSION_DENIED);
+ }
+
+
private void assertSetPermissionGrantStatePreMApp(int value) throws Exception {
assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME,
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 4cc041a..4084099 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -22,7 +22,10 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt cts-junit
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 9a09007..f2f49f9 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -52,6 +52,20 @@
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
+ <receiver
+ android:name="com.android.cts.deviceowner.CreateAndManageUserTest$SecondaryUserAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
+ <service android:name="com.android.cts.deviceowner.CreateAndManageUserTest$PrimaryUserService"
+ android:exported="true"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ </service>
<activity
android:name="com.android.cts.deviceowner.KeyManagementActivity"
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index a540c27..5e32d3e 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -17,6 +17,7 @@
package com.android.cts.deviceowner;
import android.app.ActivityManager;
+import android.app.Service;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -24,16 +25,21 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.os.Bundle;
+import android.os.IBinder;
import android.os.PersistableBundle;
-import android.os.Process;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
+
import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
@@ -50,6 +56,12 @@
private static final String SETUP_COMPLETE_EXTRA = "setupCompleteExtra";
private static final int BROADCAST_TIMEOUT = 15_000;
private static final int USER_SWITCH_DELAY = 10_000;
+
+ private static final String AFFILIATION_ID = "affiliation.id";
+ private static final String EXTRA_AFFILIATION_ID = "affiliationIdExtra";
+ private static final long ON_ENABLED_TIMEOUT_SECONDS = 120;
+
+
private PackageManager mPackageManager;
private ActivityManager mActivityManager;
private volatile boolean mReceived;
@@ -302,6 +314,28 @@
}
}
+ public void testCreateAndManageUser_StartUserInBackground() throws Exception {
+ String testUserName = "TestUser_" + System.currentTimeMillis();
+
+ // Set affiliation id to allow communication
+ mDevicePolicyManager.setAffiliationIds(getWho(), Collections.singleton(AFFILIATION_ID));
+
+ // Pack the affiliation id in a bundle so the secondary user can get it
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(EXTRA_AFFILIATION_ID, AFFILIATION_ID);
+
+ // Do not assign return value to mUserHandle, so it is not removed in tearDown.
+ UserHandle uh = mDevicePolicyManager.createAndManageUser(
+ getWho(),
+ testUserName,
+ SecondaryUserAdminReceiver.getComponentName(mContext),
+ bundle,
+ DevicePolicyManager.START_USER_IN_BACKGROUND);
+ Log.d(TAG, "User create: " + uh);
+
+ PrimaryUserService.assertCrossUserCallArrived();
+ }
+
static class LocalBroadcastReceiver extends BroadcastReceiver {
private SynchronousQueue<UserHandle> mQueue = new SynchronousQueue<UserHandle>();
@@ -318,4 +352,75 @@
return mQueue.poll(BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
+
+ public static final class PrimaryUserService extends Service {
+ private static final Semaphore mSemaphore = new Semaphore(0);
+
+ private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
+ public void onEnabledCalled() {
+ Log.d(TAG, "onEnabledCalled on primary user");
+ mSemaphore.release();
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ static void assertCrossUserCallArrived() throws Exception {
+ assertTrue(mSemaphore.tryAcquire(ON_ENABLED_TIMEOUT_SECONDS, TimeUnit.SECONDS));
+ }
+ }
+
+ public static final class SecondaryUserAdminReceiver extends DeviceAdminReceiver {
+ @Override
+ public void onEnabled(Context context, Intent intent) {
+ Log.d(TAG, "onEnabled called");
+ DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+ // Set affiliation ids
+ String affiliationId = intent.getStringExtra(EXTRA_AFFILIATION_ID);
+ dpm.setAffiliationIds(getComponentName(context),
+ Collections.singleton(affiliationId));
+ // Call all affiliated users
+ final List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(
+ getComponentName(context));
+ assertEquals(1, targetUsers.size());
+ pingTargetUser(context, dpm, targetUsers.get(0));
+ }
+
+ private void pingTargetUser(Context context, DevicePolicyManager dpm, UserHandle target) {
+ Log.d(TAG, "Pinging target: " + target);
+ final ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "onServiceConnected is called in " + Thread.currentThread().getName());
+ ICrossUserService crossUserService = ICrossUserService
+ .Stub.asInterface(service);
+ try {
+ crossUserService.onEnabledCalled();
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error when calling primary user", re);
+ // Do nothing, primary user will time out
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(TAG, "onServiceDisconnected is called");
+ }
+ };
+ final Intent serviceIntent = new Intent(context, PrimaryUserService.class);
+ assertTrue(dpm.bindDeviceAdminServiceAsUser(
+ getComponentName(context),
+ serviceIntent,
+ serviceConnection,
+ Context.BIND_AUTO_CREATE,
+ target));
+ }
+
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context, SecondaryUserAdminReceiver.class);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl
new file mode 100644
index 0000000..0cf5dcf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/ICrossUserService.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceowner;
+
+interface ICrossUserService {
+ void onEnabledCalled();
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java
new file mode 100644
index 0000000..0d2a990
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/ClearApplicationDataTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.intent.receiver;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class that writes to shared preference and verifies that the shared preference gets cleared
+ * after DPM.clearApplicationUserData was called.
+ */
+@SmallTest
+public class ClearApplicationDataTest {
+ private static final String SHARED_PREFERENCE_NAME = "test-preference";
+ private static final String I_WAS_HERE = "I-Was-Here";
+
+ private Context mContext;
+ private SharedPreferences mSharedPrefs;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mSharedPrefs = mContext.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
+ }
+
+ @Test
+ public void testWriteToSharedPreference() {
+ mSharedPrefs.edit().putBoolean(I_WAS_HERE, true).commit();
+ assertTrue(mSharedPrefs.contains(I_WAS_HERE));
+ }
+
+ @Test
+ public void testSharedPreferenceCleared() {
+ assertFalse(mSharedPrefs.contains(I_WAS_HERE));
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 70ee0d9..9d66b93 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -138,6 +138,8 @@
removeTestUsers();
// Unlock keyguard before test
wakeupAndDismissKeyguard();
+ // Go to home.
+ executeShellCommand("input keyevent KEYCODE_HOME");
}
@Override
@@ -256,6 +258,7 @@
protected void removeUser(int userId) throws Exception {
if (listUsers().contains(userId) && userId != USER_SYSTEM) {
+ waitForBroadcastIdle();
// Don't log output, as tests sometimes set no debug user restriction, which
// causes this to fail, we should still continue and remove the user.
String stopUserCommand = "am stop-user -w -f " + userId;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index b660959..ebccc1d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -253,6 +253,15 @@
executeDeviceTestMethod(".PermissionsTest", "testPermissionGrantState");
}
+ public void testPermissionGrant_developmentPermission() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ installAppPermissionAppAsUser();
+ executeDeviceTestMethod(
+ ".PermissionsTest", "testPermissionGrantState_developmentPermission");
+ }
+
/**
* Require a device for tests that use the network stack. Headless Androids running in
* data centres might need their network rules un-tampered-with in order to keep the ADB / VNC
@@ -807,6 +816,18 @@
Collections.singletonMap(ARG_ALLOW_FAILURE, Boolean.toString(allowFailures)));
}
+ public void testClearApplicationData() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ installAppAsUser(INTENT_RECEIVER_APK, mUserId);
+ runDeviceTestsAsUser(INTENT_RECEIVER_PKG, INTENT_RECEIVER_PKG + ".ClearApplicationDataTest",
+ "testWriteToSharedPreference", mUserId);
+ executeDeviceTestMethod(".ClearApplicationDataTest", "testClearApplicationData");
+ runDeviceTestsAsUser(INTENT_RECEIVER_PKG, INTENT_RECEIVER_PKG + ".ClearApplicationDataTest",
+ "testSharedPreferenceCleared", mUserId);
+ }
+
protected void executeDeviceTestClass(String className) throws Exception {
runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index a4844f5..ba0dcc0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -46,14 +46,14 @@
private static final String DEVICE_OWNER_COMPONENT = DEVICE_OWNER_PKG + "/"
+ ADMIN_RECEIVER_TEST_CLASS;
- /** The ephemeral users are implemented and supported on the device. */
- private boolean mHasEphemeralUserFeature;
+ /** Forcing ephemeral users is implemented and supported on the device. */
+ private boolean mHasForceEphemeralUserFeature;
/**
- * Ephemeral users are implemented, but unsupported on the device (because of missing split
- * system user).
+ * Force ephemeral users feature is implemented, but unsupported on the device (because of
+ * missing split system user).
*/
- private boolean mHasDisabledEphemeralUserFeature;
+ private boolean mHasDisabledForceEphemeralUserFeature;
@Override
protected void setUp() throws Exception {
@@ -67,9 +67,10 @@
fail("Failed to set device owner");
}
}
- mHasEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1) && hasUserSplit();
- mHasDisabledEphemeralUserFeature =
- mHasFeature && canCreateAdditionalUsers(1) && !hasUserSplit();
+ mHasForceEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1)
+ && hasUserSplit();
+ mHasDisabledForceEphemeralUserFeature = mHasFeature && canCreateAdditionalUsers(1)
+ && !hasUserSplit();
}
@Override
@@ -125,7 +126,7 @@
/** Tries to toggle the force-ephemeral-users on and checks it was really set. */
public void testSetForceEphemeralUsers() throws Exception {
- if (!mHasEphemeralUserFeature) {
+ if (!mHasForceEphemeralUserFeature) {
return;
}
// Set force-ephemeral-users policy and verify it was set.
@@ -136,7 +137,7 @@
* Setting force-ephemeral-users policy to true without a split system user should fail.
*/
public void testSetForceEphemeralUsersFailsWithoutSplitSystemUser() throws Exception {
- if (mHasDisabledEphemeralUserFeature) {
+ if (mHasDisabledForceEphemeralUserFeature) {
executeDeviceTestMethod(".ForceEphemeralUsersTest", "testSetForceEphemeralUsersFails");
}
}
@@ -148,7 +149,7 @@
* <p>If the current user is the system user, the other users are removed straight away.
*/
public void testRemoveUsersOnSetForceEphemeralUsers() throws Exception {
- if (!mHasEphemeralUserFeature) {
+ if (!mHasForceEphemeralUserFeature) {
return;
}
@@ -171,7 +172,7 @@
* before all other users are removed.
*/
public void testRemoveUsersOnSetForceEphemeralUsersWithUserSwitch() throws Exception {
- if (!mHasEphemeralUserFeature) {
+ if (!mHasForceEphemeralUserFeature) {
return;
}
@@ -206,7 +207,7 @@
/** The users created after setting force-ephemeral-users policy to true must be ephemeral. */
public void testCreateUserAfterSetForceEphemeralUsers() throws Exception {
- if (!mHasEphemeralUserFeature) {
+ if (!mHasForceEphemeralUserFeature) {
return;
}
@@ -221,7 +222,7 @@
* Test creating an epehemeral user using the DevicePolicyManager's createAndManageUser method.
*/
public void testCreateAndManageEphemeralUser() throws Exception {
- if (!mHasEphemeralUserFeature) {
+ if (!mHasFeature || !canCreateAdditionalUsers(1)) {
return;
}
@@ -236,17 +237,6 @@
assertEquals("Ephemeral flag must be set", FLAG_EPHEMERAL, flags & FLAG_EPHEMERAL);
}
- /**
- * Test that creating an epehemeral user using the DevicePolicyManager's createAndManageUser
- * method fails on systems without the split system user.
- */
- public void testCreateAndManageEphemeralUserFailsWithoutSplitSystemUser() throws Exception {
- if (mHasDisabledEphemeralUserFeature) {
- executeDeviceTestMethod(
- ".CreateAndManageUserTest", "testCreateAndManageEphemeralUserFails");
- }
- }
-
// Disabled due to b/29072728
// public void testCreateAndManageUser_SkipSetupWizard() throws Exception {
// if (mHasCreateAndManageUserFeature) {
@@ -276,6 +266,13 @@
}
}
+ public void testCreateAndManageUser_StartUserInBackground() throws Exception {
+ if (mHasFeature && canCreateAdditionalUsers(1)) {
+ executeDeviceTestMethod(".CreateAndManageUserTest",
+ "testCreateAndManageUser_StartUserInBackground");
+ }
+ }
+
public void testUserAddedOrRemovedBroadcasts() throws Exception {
if (mHasFeature && canCreateAdditionalUsers(1)) {
executeDeviceTestMethod(".CreateAndManageUserTest",
@@ -440,6 +437,7 @@
setProfileOwnerOrFail(DEVICE_OWNER_COMPONENT, userId);
switchUser(userId);
+ wakeupAndDismissKeyguard();
// Setting the same affiliation ids on both users and running the lock task tests.
runDeviceTestsAsUser(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
index df4a47c..84bdd7d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/EphemeralUserTest.java
@@ -17,7 +17,7 @@
package com.android.cts.devicepolicy;
/**
- * Tests for emphemeral users and profiles.
+ * Tests for ephemeral users and profiles.
*/
public class EphemeralUserTest extends BaseDevicePolicyTest {
@@ -35,7 +35,7 @@
/** The user should have the ephemeral flag set if it was created as ephemeral. */
public void testCreateEphemeralUser() throws Exception {
- if (!mHasFeature || !hasUserSplit()) {
+ if (!mHasFeature) {
return;
}
int userId = createUser(FLAG_EPHEMERAL);
@@ -59,7 +59,8 @@
*/
public void testProfileInheritsEphemeral() throws Exception {
if (!mHasFeature || !hasDeviceFeature("android.software.managed_users")
- || !hasUserSplit() || !canCreateAdditionalUsers(2)) {
+ || !canCreateAdditionalUsers(2)
+ || !hasUserSplit()) {
return;
}
int userId = createUser(FLAG_EPHEMERAL);
@@ -72,7 +73,7 @@
* Ephemeral user should be automatically removed after it is stopped.
*/
public void testRemoveEphemeralOnStop() throws Exception {
- if (!mHasFeature || !hasUserSplit()) {
+ if (!mHasFeature) {
return;
}
int userId = createUser(FLAG_EPHEMERAL);
@@ -87,7 +88,7 @@
* and not ephemeral when the feature is not set.
*/
public void testEphemeralGuestFeature() throws Exception {
- if (!mHasFeature || !hasUserSplit()) {
+ if (!mHasFeature) {
return;
}
// Create a guest user.
@@ -103,20 +104,6 @@
}
}
- /**
- * Test that creating an ephemeral user fails on systems without the split system user.
- */
- public void testCreateEphemeralWithoutUserSplitFails() throws Exception {
- if (!mHasFeature || hasUserSplit()) {
- return;
- }
- String command ="pm create-user --ephemeral " + "TestUser_" + System.currentTimeMillis();
- String commandOutput = getDevice().executeShellCommand(command);
-
- assertEquals("Creating the epehemeral user should fail.",
- "Error: couldn't create User.", commandOutput.trim());
- }
-
private boolean getGuestUsersEphemeral() throws Exception {
String commandOutput = getDevice().executeShellCommand("dumpsys user");
String[] outputLines = commandOutput.split("\n");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
index ef7099b..b71c4c87 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileProvisioningSingleAdminTest.java
@@ -15,8 +15,6 @@
*/
package com.android.cts.devicepolicy;
-import org.junit.Test;
-
/**
* This class tests the provisioning flow with an APK that declares a single receiver with
* BIND_DEVICE_ADMIN permissions, which was a requirement for the app sending the
@@ -54,7 +52,6 @@
super.tearDown();
}
- @Test
public void testEXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME() throws Exception {
if (!mHasFeature) {
return;
diff --git a/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java b/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java
new file mode 100644
index 0000000..24f3d2a
--- /dev/null
+++ b/hostsidetests/incident/src/com/android/server/cts/PrintProtoTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts;
+
+import android.service.print.PrintServiceDumpProto;
+import android.service.print.PrintSpoolerStateProto;
+import android.service.print.PrintUserStateProto;
+
+import com.android.tradefed.log.LogUtil;
+
+/**
+ * Test proto dump of print
+ */
+public class PrintProtoTest extends ProtoDumpTestCase {
+ /**
+ * Test that print dump is reasonable
+ *
+ * @throws Exception
+ */
+ public void testDump() throws Exception {
+ // If the device doesn't support printing, then pass.
+ if (!getDevice().hasFeature("android.software.print")) {
+ LogUtil.CLog.d("Bypass as android.software.print is not supported.");
+ return;
+ }
+
+ PrintServiceDumpProto dump = getDump(PrintServiceDumpProto.parser(),
+ "dumpsys print --proto");
+
+ assertTrue(dump.getUserStatesCount() > 0);
+
+ PrintUserStateProto userState = dump.getUserStatesList().get(0);
+ assertEquals(0, userState.getUserId());
+ }
+}
diff --git a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
index 3c1f14e..e7be900 100644
--- a/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
+++ b/hostsidetests/media/bitstreams/src/android/media/cts/bitstreams/ReportProcessor.java
@@ -140,6 +140,8 @@
instrTest.addIncludeFilter(fullTestName);
instrTest.setTestTimeout(testTimeout);
instrTest.setShellTimeout(shellTimeout);
+ // disable rerun mode to avoid collecting tests first then running.
+ instrTest.setRerunMode(false);
for (Entry<String, String> e : getArgs().entrySet()) {
instrTest.addInstrumentationArg(e.getKey(), e.getValue());
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index d2c0873..133a43b 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -127,6 +127,19 @@
assertBackgroundNetworkAccess(false);
}
+ public void testBackgroundNetworkAccess_tempWhitelisted() throws Exception {
+ if (!isSupported()) return;
+
+ setAppIdle(true);
+ assertBackgroundNetworkAccess(false);
+
+ addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(true);
+ // Wait until the whitelist duration is expired.
+ SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(false);
+ }
+
public void testBackgroundNetworkAccess_disabled() throws Exception {
if (!isSupported()) return;
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index e65db31..bd43cc8 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -107,6 +107,8 @@
private static final String APP_NOT_FOREGROUND_ERROR = "app_not_fg";
+ protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec
+
protected Context mContext;
protected Instrumentation mInstrumentation;
protected ConnectivityManager mCm;
@@ -706,6 +708,12 @@
+ ". Full list: " + uids);
}
+ protected void addTempPowerSaveModeWhitelist(String packageName, long duration)
+ throws Exception {
+ Log.i(TAG, "Adding pkg " + packageName + " to temp-power-save-mode whitelist");
+ executeShellCommand("dumpsys deviceidle tempwhitelist -d " + duration + " " + packageName);
+ }
+
protected void assertPowerSaveModeWhitelist(String packageName, boolean expected)
throws Exception {
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
index 5248255..76332be 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
@@ -15,6 +15,7 @@
*/
package com.android.cts.net.hostside;
+import android.os.SystemClock;
import android.util.Log;
/**
@@ -271,4 +272,55 @@
setDozeMode(false);
}
}
+
+ public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
+ if (!isSupported()) {
+ return;
+ }
+ if (!isDozeModeEnabled()) {
+ Log.i(TAG, "Skipping " + getClass() + "." + getName()
+ + "() because device does not support Doze Mode");
+ return;
+ }
+
+ setDozeMode(true);
+ setAppIdle(true);
+
+ try {
+ assertBackgroundNetworkAccess(false);
+
+ addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(true);
+
+ // Wait until the whitelist duration is expired.
+ SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(false);
+ } finally {
+ setAppIdle(false);
+ setDozeMode(false);
+ }
+ }
+
+ public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
+ if (!isSupported()) {
+ return;
+ }
+
+ setBatterySaverMode(true);
+ setAppIdle(true);
+
+ try {
+ assertBackgroundNetworkAccess(false);
+
+ addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(true);
+
+ // Wait until the whitelist duration is expired.
+ SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+ assertBackgroundNetworkAccess(false);
+ } finally {
+ setAppIdle(false);
+ setBatterySaverMode(false);
+ }
+ }
}
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index bf3fc08..fe9d36c 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -146,6 +146,11 @@
"testBackgroundNetworkAccess_whitelisted");
}
+ public void testAppIdleMetered_tempWhitelisted() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ "testBackgroundNetworkAccess_tempWhitelisted");
+ }
+
public void testAppIdleMetered_enabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_enabled");
@@ -166,6 +171,11 @@
"testBackgroundNetworkAccess_whitelisted");
}
+ public void testAppIdleNonMetered_tempWhitelisted() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ "testBackgroundNetworkAccess_tempWhitelisted");
+ }
+
public void testAppIdleNonMetered_enabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_enabled");
@@ -261,6 +271,16 @@
"testDozeAndAppIdle_powerSaveWhitelists");
}
+ public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ "testAppIdleAndDoze_tempPowerSaveWhitelists");
+ }
+
+ public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ "testAppIdleAndBatterySaver_tempPowerSaveWhitelists");
+ }
+
/*******************
* Helper methods. *
*******************/
diff --git a/hostsidetests/security/securityPatch/Bug-33039685/Android.mk b/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
index 701138d..17af326 100644
--- a/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33039685/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-33299365/Android.mk b/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
index 8a7b047..6ba7ed9 100644
--- a/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-33299365/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-34173755/Android.mk b/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
index f07cf4e..a64a37c 100644
--- a/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-34173755/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-34624155/Android.mk b/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
index 0f1a737..95e8c24 100644
--- a/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-34624155/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35139833/Android.mk b/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
index 8865fa9..bc49a79 100644
--- a/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35139833/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35468048/Android.mk b/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
index 9213fa3..88166b8 100644
--- a/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35468048/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35470735/Android.mk b/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
index 1f14c2c..1a42fd2 100644
--- a/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35470735/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35644510/Android.mk b/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
index efe00f2..3a8edf6 100644
--- a/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35644510/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35676417/Android.mk b/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
index 41ba50d..06ab345 100644
--- a/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35676417/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35764875/Android.mk b/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
index e62bdd2..4d6f4fc 100644
--- a/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35764875/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/
diff --git a/hostsidetests/security/securityPatch/Bug-35950388/Android.mk b/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
index 824e86f..8289311 100644
--- a/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35950388/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_C_INCLUDES += include
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/Bug-35950805/Android.mk b/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
index 11c4e46..b3dec07 100644
--- a/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
+++ b/hostsidetests/security/securityPatch/Bug-35950805/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
index 0a5b344..f4f2c57 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-9678/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
index fa5539b..f3ab0d6 100644
--- a/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
+++ b/hostsidetests/security/securityPatch/CVE-2017-9692/Android.mk
@@ -22,7 +22,7 @@
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts vts
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
index 993ba94..ec07ac6 100644
--- a/hostsidetests/services/activityandwindowmanager/util/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/util/Android.mk
@@ -23,7 +23,9 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed host-libprotobuf-java-full
+
+LOCAL_STATIC_JAVA_LIBRARIES := platformprotos
LOCAL_MODULE := cts-amwm-util
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index 0cdf13e..6be01ec 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -20,11 +20,27 @@
import static android.server.cts.StateLogger.log;
import static android.server.cts.StateLogger.logE;
-import com.android.tradefed.device.CollectingOutputReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
+import android.graphics.RectProto;
+import com.android.server.wm.proto.AppWindowTokenProto;
+import com.android.server.wm.proto.AppTransitionProto;
+import com.android.server.wm.proto.DisplayProto;
+import com.android.server.wm.proto.IdentifierProto;
+import com.android.server.wm.proto.PinnedStackControllerProto;
+import com.android.server.wm.proto.StackProto;
+import com.android.server.wm.proto.TaskProto;
+import com.android.server.wm.proto.WindowManagerServiceProto;
+import com.android.server.wm.proto.WindowStateAnimatorProto;
+import com.android.server.wm.proto.WindowStateProto;
+import com.android.server.wm.proto.WindowSurfaceControllerProto;
+import com.android.server.wm.proto.WindowTokenProto;
+import android.view.DisplayInfoProto;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
import com.android.tradefed.device.ITestDevice;
-import java.awt.*;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.awt.Rectangle;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -32,8 +48,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class WindowManagerState {
@@ -55,63 +69,10 @@
public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
- private static final String DUMPSYS_WINDOW = "dumpsys window -a";
+ private static final String DUMPSYS_WINDOW = "dumpsys window -a --proto";
- private static final Pattern sWindowPattern =
- Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:");
- private static final Pattern sStartingWindowPattern =
- Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Starting (.+)\\}\\:");
- private static final Pattern sExitingWindowPattern =
- Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+) EXITING\\}\\:");
- private static final Pattern sDebuggerWindowPattern =
- Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger: (.+)\\}\\:");
-
- private static final Pattern sFocusedWindowPattern = Pattern.compile(
- "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) (\\S+)\\}");
- private static final Pattern sAppErrorFocusedWindowPattern = Pattern.compile(
- "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Application Error\\: (\\S+)\\}");
- private static final Pattern sWaitingForDebuggerFocusedWindowPattern = Pattern.compile(
- "mCurrentFocus=Window\\{([0-9a-fA-F]+) u(\\d+) Waiting For Debugger\\: (\\S+)\\}");
-
- private static final Pattern sFocusedAppPattern =
- Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) "
- + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)");
- private static final Pattern sStableBoundsPattern = Pattern.compile(
- "mStable=\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\)");
- private static final Pattern sDefaultPinnedStackBoundsPattern = Pattern.compile(
- "defaultBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
- private static final Pattern sPinnedStackMovementBoundsPattern = Pattern.compile(
- "movementBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
- private static final Pattern sRotationPattern = Pattern.compile(
- "mRotation=(\\d).*");
- private static final Pattern sLastOrientationPattern = Pattern.compile(
- ".*mLastOrientation=(\\d)");
-
- private static final Pattern sLastAppTransitionPattern =
- Pattern.compile("mLastUsedAppTransition=(.+)");
- private static final Pattern sAppTransitionStatePattern =
- Pattern.compile("mAppTransitionState=(.+)");
-
- private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
-
- private static final Pattern sInputMethodWindowPattern =
- Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*");
-
- private static final Pattern sDisplayIdPattern =
- Pattern.compile("Display: mDisplayId=(\\d+)");
-
- private static final Pattern sDisplayFrozenPattern =
- Pattern.compile("mDisplayFrozen=([a-z]*) .*");
-
- private static final Pattern sDockedStackMinimizedPattern =
- Pattern.compile("mMinimizedDock=([a-z]*)");
-
- private static final Pattern[] sExtractStackExitPatterns = {
- sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
- sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
- sWaitingForDebuggerFocusedWindowPattern,
- sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern,
- sPinnedStackMovementBoundsPattern, sDisplayIdPattern, sDockedStackMinimizedPattern};
+ private static final String STARTING_WINDOW_PREFIX = "Starting ";
+ private static final String DEBUGGER_WINDOW_PREFIX = "Waiting For Debugger: ";
// Windows in z-order with the top most at the front of the list.
private List<WindowState> mWindowStates = new ArrayList();
@@ -127,20 +88,20 @@
private String mAppTransitionState = null;
private String mInputMethodWindowAppToken = null;
private Rectangle mStableBounds = new Rectangle();
- private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
- private final Rectangle mPinnedStackMovementBounds = new Rectangle();
+ private Rectangle mDefaultPinnedStackBounds = new Rectangle();
+ private Rectangle mPinnedStackMovementBounds = new Rectangle();
private final LinkedList<String> mSysDump = new LinkedList();
private int mRotation;
private int mLastOrientation;
private boolean mDisplayFrozen;
private boolean mIsDockedStackMinimized;
- void computeState(ITestDevice device) throws DeviceNotAvailableException {
+ void computeState(ITestDevice device) throws Exception {
// It is possible the system is in the middle of transition to the right state when we get
// the dump. We try a few times to get the information we need before giving up.
int retriesLeft = 3;
boolean retry = false;
- String dump = null;
+ byte[] dump = null;
log("==============================");
log(" WindowManagerState ");
@@ -157,18 +118,18 @@
}
}
- final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ final CollectingByteOutputReceiver outputReceiver = new CollectingByteOutputReceiver();
device.executeShellCommand(DUMPSYS_WINDOW, outputReceiver);
dump = outputReceiver.getOutput();
- parseSysDump(dump);
+ try {
+ parseSysDumpProto(dump);
+ } catch (InvalidProtocolBufferException ex) {
+ System.out.println(new String(dump, StandardCharsets.UTF_8));
+ }
retry = mWindowStates.isEmpty() || mFocusedApp == null;
} while (retry && retriesLeft-- > 0);
- if (retry) {
- log(dump);
- }
-
if (mWindowStates.isEmpty()) {
logE("No Windows found...");
}
@@ -180,181 +141,54 @@
}
}
- private void parseSysDump(String sysDump) {
+ private void parseSysDumpProto(byte[] sysDump) throws Exception {
reset();
-
- Collections.addAll(mSysDump, sysDump.split("\\n"));
-
- int currentDisplayId = DEFAULT_DISPLAY_ID;
- while (!mSysDump.isEmpty()) {
- final Display display =
- Display.create(mSysDump, sExtractStackExitPatterns);
- if (display != null) {
- log(display.toString());
- mDisplays.add(display);
- currentDisplayId = display.mDisplayId;
- mDisplayStacks.put(currentDisplayId, new ArrayList<>());
- continue;
- }
-
- final WindowStack stack =
- WindowStack.create(mSysDump, sStackIdPattern, sExtractStackExitPatterns);
-
- if (stack != null) {
+ List<WindowState> allWindows = new ArrayList<>();
+ Map<String, WindowState> windowMap = new HashMap<>();
+ WindowManagerServiceProto state = WindowManagerServiceProto.parser().parseFrom(sysDump);
+ if (state.hasFocusedWindow()) {
+ mFocusedWindow = state.getFocusedWindow().getTitle();
+ }
+ mFocusedApp = state.getFocusedApp();
+ for (int i = 0; i < state.getDisplaysCount(); i++) {
+ DisplayProto displayProto = state.getDisplays(i);
+ final Display display = new Display(displayProto);
+ mDisplays.add(display);
+ allWindows.addAll(display.getWindows());
+ List<WindowStack> stacks = new ArrayList<>();
+ for (int j = 0; j < displayProto.getStacksCount(); j++) {
+ StackProto stackProto = displayProto.getStacks(j);
+ final WindowStack stack = new WindowStack(stackProto);
mStacks.add(stack);
- mDisplayStacks.get(currentDisplayId).add(stack);
- continue;
+ stacks.add(stack);
+ allWindows.addAll(stack.getWindows());
}
+ mDisplayStacks.put(display.mDisplayId, stacks);
-
- final WindowState ws = WindowState.create(mSysDump, sExtractStackExitPatterns);
- if (ws != null) {
- log(ws.toString());
-
- // Check to see if we are in the middle of transitioning. If we are, we want to
- // skip dumping until window manager is done transitioning windows.
- if (ws.isStartingWindow()) {
- log("Skipping dump due to starting window transition...");
- return;
- }
-
- if (ws.isExitingWindow()) {
- log("Skipping dump due to exiting window transition...");
- return;
- }
-
- mWindowStates.add(ws);
- continue;
- }
-
- final String line = mSysDump.pop().trim();
-
- Matcher matcher = sFocusedWindowPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String focusedWindow = matcher.group(3);
- log(focusedWindow);
- mFocusedWindow = focusedWindow;
- continue;
- }
-
- matcher = sAppErrorFocusedWindowPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String focusedWindow = matcher.group(3);
- log(focusedWindow);
- mFocusedWindow = focusedWindow;
- continue;
- }
-
- matcher = sWaitingForDebuggerFocusedWindowPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String focusedWindow = matcher.group(3);
- log(focusedWindow);
- mFocusedWindow = focusedWindow;
- continue;
- }
-
- matcher = sFocusedAppPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String focusedApp = matcher.group(5);
- log(focusedApp);
- mFocusedApp = focusedApp;
- continue;
- }
-
- matcher = sAppTransitionStatePattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String appTransitionState = matcher.group(1);
- log(appTransitionState);
- mAppTransitionState = appTransitionState;
- continue;
- }
-
- matcher = sLastAppTransitionPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String lastAppTransitionPattern = matcher.group(1);
- log(lastAppTransitionPattern);
- mLastTransition = lastAppTransitionPattern;
- continue;
- }
-
- matcher = sStableBoundsPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- int left = Integer.parseInt(matcher.group(1));
- int top = Integer.parseInt(matcher.group(2));
- int right = Integer.parseInt(matcher.group(3));
- int bottom = Integer.parseInt(matcher.group(4));
- mStableBounds.setBounds(left, top, right - left, bottom - top);
- log(mStableBounds.toString());
- continue;
- }
-
- matcher = sDefaultPinnedStackBoundsPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- int left = Integer.parseInt(matcher.group(1));
- int top = Integer.parseInt(matcher.group(2));
- int right = Integer.parseInt(matcher.group(3));
- int bottom = Integer.parseInt(matcher.group(4));
- mDefaultPinnedStackBounds.setBounds(left, top, right - left, bottom - top);
- log(mDefaultPinnedStackBounds.toString());
- continue;
- }
-
- matcher = sPinnedStackMovementBoundsPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- int left = Integer.parseInt(matcher.group(1));
- int top = Integer.parseInt(matcher.group(2));
- int right = Integer.parseInt(matcher.group(3));
- int bottom = Integer.parseInt(matcher.group(4));
- mPinnedStackMovementBounds.setBounds(left, top, right - left, bottom - top);
- log(mPinnedStackMovementBounds.toString());
- continue;
- }
-
- matcher = sInputMethodWindowPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mInputMethodWindowAppToken = matcher.group(1);
- log(mInputMethodWindowAppToken);
- continue;
- }
-
- matcher = sRotationPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mRotation = Integer.parseInt(matcher.group(1));
- continue;
- }
-
- matcher = sLastOrientationPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mLastOrientation = Integer.parseInt(matcher.group(1));
- continue;
- }
-
- matcher = sDisplayFrozenPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mDisplayFrozen = Boolean.parseBoolean(matcher.group(1));
- continue;
- }
-
- matcher = sDockedStackMinimizedPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mIsDockedStackMinimized = Boolean.parseBoolean(matcher.group(1));
- continue;
+ // use properties from the default display only
+ if (display.getDisplayId() == DEFAULT_DISPLAY_ID) {
+ mIsDockedStackMinimized = displayProto.getDockedStackDividerController().getMinimizedDock();
+ PinnedStackControllerProto pinnedStackProto = displayProto.getPinnedStackController();
+ mDefaultPinnedStackBounds = WindowContainer.extractBounds(pinnedStackProto.getDefaultBounds());
+ mPinnedStackMovementBounds = WindowContainer.extractBounds(pinnedStackProto.getMovementBounds());
}
}
+ for (WindowState w : allWindows) {
+ windowMap.put(w.getToken(), w);
+ }
+ for (int i = 0; i < state.getWindowsCount(); i++) {
+ IdentifierProto identifierProto = state.getWindows(i);
+ String hash_code = Integer.toHexString(identifierProto.getHashCode());
+ mWindowStates.add(windowMap.get(hash_code));
+ }
+ mStableBounds = WindowContainer.extractBounds(state.getPolicy().getStableBounds());
+ mInputMethodWindowAppToken = Integer.toHexString(state.getInputMethodWindow().getHashCode());
+ mDisplayFrozen = state.getDisplayFrozen();
+ mRotation = state.getRotation();
+ mLastOrientation = state.getLastOrientation();
+ AppTransitionProto appTransitionProto = state.getAppTransition();
+ mAppTransitionState = appTransitionProto.getAppTransitionState().name();
+ mLastTransition = appTransitionProto.getLastUsedAppTransition().name();
}
void getMatchingWindowTokens(final String windowName, List<String> tokenList) {
@@ -582,80 +416,23 @@
static class WindowStack extends WindowContainer {
- private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)");
- private static final Pattern sWindowAnimationBackgroundSurfacePattern =
- Pattern.compile("mWindowAnimationBackgroundSurface:");
-
int mStackId;
ArrayList<WindowTask> mTasks = new ArrayList();
boolean mWindowAnimationBackgroundSurfaceShowing;
- private WindowStack() {
-
- }
-
- static WindowStack create(
- LinkedList<String> dump, Pattern stackIdPattern, Pattern[] exitPatterns) {
- final String line = dump.peek().trim();
-
- final Matcher matcher = stackIdPattern.matcher(line);
- if (!matcher.matches()) {
- // Not a stack.
- return null;
+ WindowStack(StackProto proto) {
+ mStackId = proto.getId();
+ mFullscreen = proto.getFillsParent();
+ if (proto.hasBounds()) {
+ mBounds = extractBounds(proto.getBounds());
}
- // For the stack Id line we just read.
- dump.pop();
-
- final WindowStack stack = new WindowStack();
- log(line);
- final String stackId = matcher.group(1);
- log(stackId);
- stack.mStackId = Integer.parseInt(stackId);
- stack.extract(dump, exitPatterns);
- return stack;
- }
-
- void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
- final List<Pattern> taskExitPatterns = new ArrayList();
- Collections.addAll(taskExitPatterns, exitPatterns);
- taskExitPatterns.add(sTaskIdPattern);
- taskExitPatterns.add(sWindowAnimationBackgroundSurfacePattern);
- final Pattern[] taskExitPatternsArray =
- taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
-
- while (!doneExtracting(dump, exitPatterns)) {
- final WindowTask task =
- WindowTask.create(dump, sTaskIdPattern, taskExitPatternsArray);
-
- if (task != null) {
- mTasks.add(task);
- continue;
- }
-
- final String line = dump.pop().trim();
-
- if (extractFullscreen(line)) {
- continue;
- }
-
- if (extractBounds(line)) {
- continue;
- }
-
- if (extractWindowAnimationBackgroundSurface(line)) {
- continue;
- }
+ for (int i = 0; i < proto.getTasksCount(); i++) {
+ TaskProto taskProto = proto.getTasks(i);
+ WindowTask task = new WindowTask(taskProto);
+ mTasks.add(task);
+ mSubWindows.addAll(task.getWindows());
}
- }
-
- boolean extractWindowAnimationBackgroundSurface(String line) {
- if (sWindowAnimationBackgroundSurfacePattern.matcher(line).matches()) {
- log(line);
- mWindowAnimationBackgroundSurfaceShowing = true;
- return true;
- }
- return false;
+ mWindowAnimationBackgroundSurfaceShowing = proto.getAnimationBackgroundSurfaceIsDimming();
}
WindowTask getTask(int taskId) {
@@ -673,140 +450,47 @@
}
static class WindowTask extends WindowContainer {
- private static final Pattern sTempInsetBoundsPattern =
- Pattern.compile("mTempInsetBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
-
- private static final Pattern sAppTokenPattern = Pattern.compile(
- "Activity #(\\d+) AppWindowToken\\{(\\S+) token=Token\\{(\\S+) "
- + "ActivityRecord\\{(\\S+) u(\\d+) (\\S+) t(\\d+)\\}\\}\\}");
-
int mTaskId;
Rectangle mTempInsetBounds;
List<String> mAppTokens = new ArrayList();
- private WindowTask() {
- }
-
- static WindowTask create(
- LinkedList<String> dump, Pattern taskIdPattern, Pattern[] exitPatterns) {
- final String line = dump.peek().trim();
-
- final Matcher matcher = taskIdPattern.matcher(line);
- if (!matcher.matches()) {
- // Not a task.
- return null;
+ WindowTask(TaskProto proto) {
+ mTaskId = proto.getId();
+ mFullscreen = proto.getFillsParent();
+ if (proto.hasBounds()) {
+ mBounds = extractBounds(proto.getBounds());
}
- // For the task Id line we just read.
- dump.pop();
-
- final WindowTask task = new WindowTask();
- log(line);
- final String taskId = matcher.group(1);
- log(taskId);
- task.mTaskId = Integer.parseInt(taskId);
- task.extract(dump, exitPatterns);
- return task;
- }
-
- private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
- while (!doneExtracting(dump, exitPatterns)) {
- final String line = dump.pop().trim();
-
- if (extractFullscreen(line)) {
- continue;
- }
-
- if (extractBounds(line)) {
- continue;
- }
-
- Matcher matcher = sTempInsetBoundsPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- mTempInsetBounds = extractBounds(matcher);
- }
-
- matcher = sAppTokenPattern.matcher(line);
- if (matcher.matches()) {
- log(line);
- final String appToken = matcher.group(6);
- log(appToken);
- mAppTokens.add(appToken);
- continue;
+ for (int i = 0; i < proto.getAppWindowTokensCount(); i++) {
+ AppWindowTokenProto appWindowTokenProto = proto.getAppWindowTokens(i);
+ mAppTokens.add(appWindowTokenProto.getName());
+ WindowTokenProto windowTokenProto = appWindowTokenProto.getWindowToken();
+ for (int j = 0; j < windowTokenProto.getWindowsCount(); j++) {
+ WindowStateProto windowProto = windowTokenProto.getWindows(j);
+ WindowState window = new WindowState(windowProto);
+ mSubWindows.add(window);
+ mSubWindows.addAll(window.getWindows());
}
}
+ mTempInsetBounds = extractBounds(proto.getTempInsetBounds());
}
}
static abstract class WindowContainer {
- protected static final Pattern sFullscreenPattern = Pattern.compile("mFillsParent=(\\S+)");
- protected static final Pattern sBoundsPattern =
- Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]");
protected boolean mFullscreen;
protected Rectangle mBounds;
+ protected List<WindowState> mSubWindows = new ArrayList<>();
- static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {
- if (dump.isEmpty()) {
- return true;
- }
- final String line = dump.peek().trim();
-
- for (Pattern pattern : exitPatterns) {
- if (pattern.matcher(line).matches()) {
- return true;
- }
- }
- return false;
- }
-
- boolean extractFullscreen(String line) {
- final Matcher matcher = sFullscreenPattern.matcher(line);
- if (!matcher.matches()) {
- return false;
- }
- log(line);
- final String fullscreen = matcher.group(1);
- log(fullscreen);
- mFullscreen = Boolean.valueOf(fullscreen);
- return true;
- }
-
- boolean extractBounds(String line) {
- final Matcher matcher = sBoundsPattern.matcher(line);
- if (!matcher.matches()) {
- return false;
- }
- log(line);
- mBounds = extractBounds(matcher);
- return true;
- }
-
- static Rectangle extractBounds(Matcher matcher) {
- final int left = Integer.valueOf(matcher.group(1));
- final int top = Integer.valueOf(matcher.group(2));
- final int right = Integer.valueOf(matcher.group(3));
- final int bottom = Integer.valueOf(matcher.group(4));
+ static Rectangle extractBounds(RectProto rectProto) {
+ final int left = rectProto.getLeft();
+ final int top = rectProto.getTop();
+ final int right = rectProto.getRight();
+ final int bottom = rectProto.getBottom();
final Rectangle rect = new Rectangle(left, top, right - left, bottom - top);
-
- log(rect.toString());
return rect;
}
- static void extractMultipleBounds(Matcher matcher, int groupIndex, Rectangle... rectList) {
- for (Rectangle rect : rectList) {
- if (rect == null) {
- return;
- }
- final int left = Integer.valueOf(matcher.group(groupIndex++));
- final int top = Integer.valueOf(matcher.group(groupIndex++));
- final int right = Integer.valueOf(matcher.group(groupIndex++));
- final int bottom = Integer.valueOf(matcher.group(groupIndex++));
- rect.setBounds(left, top, right - left, bottom - top);
- }
- }
-
Rectangle getBounds() {
return mBounds;
}
@@ -814,21 +498,43 @@
boolean isFullscreen() {
return mFullscreen;
}
+
+ List<WindowState> getWindows() {
+ return mSubWindows;
+ }
}
static class Display extends WindowContainer {
- private static final String TAG = "[Display] ";
-
- private static final Pattern sDisplayInfoPattern =
- Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
private final int mDisplayId;
private Rectangle mDisplayRect = new Rectangle();
private Rectangle mAppRect = new Rectangle();
private int mDpi;
- private Display(int displayId) {
- mDisplayId = displayId;
+ public Display(DisplayProto proto) {
+ mDisplayId = proto.getId();
+ for (int i = 0; i < proto.getAboveAppWindowsCount(); i++) {
+ addWindowsFromTokenProto(proto.getAboveAppWindows(i));
+ }
+ for (int i = 0; i < proto.getBelowAppWindowsCount(); i++) {
+ addWindowsFromTokenProto(proto.getBelowAppWindows(i));
+ }
+ for (int i = 0; i < proto.getImeWindowsCount(); i++) {
+ addWindowsFromTokenProto(proto.getImeWindows(i));
+ }
+ mDpi = proto.getDpi();
+ DisplayInfoProto infoProto = proto.getDisplayInfo();
+ mDisplayRect.setBounds(0, 0, infoProto.getLogicalWidth(), infoProto.getLogicalHeight());
+ mAppRect.setBounds(0, 0, infoProto.getAppWidth(), infoProto.getAppHeight());
+ }
+
+ private void addWindowsFromTokenProto(WindowTokenProto proto) {
+ for (int j = 0; j < proto.getWindowsCount(); j++) {
+ WindowStateProto windowProto = proto.getWindows(j);
+ WindowState childWindow = new WindowState(windowProto);
+ mSubWindows.add(childWindow);
+ mSubWindows.addAll(childWindow.getWindows());
+ }
}
int getDisplayId() {
@@ -847,48 +553,6 @@
return mAppRect;
}
- static Display create(LinkedList<String> dump, Pattern[] exitPatterns) {
- // TODO: exit pattern for displays?
- final String line = dump.peek().trim();
-
- Matcher matcher = sDisplayIdPattern.matcher(line);
- if (!matcher.matches()) {
- return null;
- }
-
- log(TAG + "DISPLAY_ID: " + line);
- dump.pop();
-
- final int displayId = Integer.valueOf(matcher.group(1));
- final Display display = new Display(displayId);
- display.extract(dump, exitPatterns);
- return display;
- }
-
- private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
- while (!doneExtracting(dump, exitPatterns)) {
- final String line = dump.pop().trim();
-
- final Matcher matcher = sDisplayInfoPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "DISPLAY_INFO: " + line);
- mDpi = Integer.valueOf(matcher.group(2));
-
- final int displayWidth = Integer.valueOf(matcher.group(3));
- final int displayHeight = Integer.valueOf(matcher.group(4));
- mDisplayRect.setBounds(0, 0, displayWidth, displayHeight);
-
- final int appWidth = Integer.valueOf(matcher.group(5));
- final int appHeight = Integer.valueOf(matcher.group(6));
- mAppRect.setBounds(0, 0, appWidth, appHeight);
-
- // break as we don't need other info for now
- break;
- }
- // Extract other info here if needed
- }
- }
-
@Override
public String toString() {
return "Display #" + mDisplayId + ": mDisplayRect=" + mDisplayRect
@@ -906,31 +570,7 @@
private static final int WINDOW_TYPE_EXITING = 2;
private static final int WINDOW_TYPE_DEBUGGER = 3;
- private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]";
- private static final String NEGATIVE_VALUES_ALLOWED_RECT_STR =
- "\\[([-\\d]+),([-\\d]+)\\]\\[([-\\d]+),([-\\d]+)\\]";
- private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+");
- private static final Pattern sFramePattern =
- Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
- private static final Pattern sContentFramePattern =
- Pattern.compile("content=" + RECT_STR + " .+");
- private static final Pattern sWindowAssociationPattern =
- Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
- private static final Pattern sSurfaceInsetsPattern =
- Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+");
- private static final Pattern sContentInsetsPattern =
- Pattern.compile("Cur insets.+content=" + NEGATIVE_VALUES_ALLOWED_RECT_STR + ".+");
- private static final Pattern sGivenContentInsetsPattern =
- Pattern.compile("mGivenContentInsets=" + RECT_STR + ".+");
- private static final Pattern sCropPattern =
- Pattern.compile(".+mLastClipRect=" + RECT_STR + ".*");
- private static final Pattern sSurfacePattern =
- Pattern.compile("Surface: shown=(\\S+) layer=(\\d+) alpha=[\\d.]+ rect=\\([\\d.-]+,[\\d.-]+\\) [\\d.]+ x [\\d.]+.*");
- private static final Pattern sAttrsPattern=
- Pattern.compile("mAttrs=WM\\.LayoutParams\\{.*ty=(\\d+).*\\}");
-
-
- private final String mName;
+ private String mName;
private final String mAppToken;
private final int mWindowType;
private int mType;
@@ -947,11 +587,45 @@
private Rectangle mGivenContentInsets = new Rectangle();
private Rectangle mCrop = new Rectangle();
-
- private WindowState(Matcher matcher, int windowType) {
- mName = matcher.group(4);
- mAppToken = matcher.group(2);
- mWindowType = windowType;
+ WindowState (WindowStateProto proto) {
+ IdentifierProto identifierProto = proto.getIdentifier();
+ mName = identifierProto.getTitle();
+ mAppToken = Integer.toHexString(identifierProto.getHashCode());
+ mDisplayId = proto.getDisplayId();
+ mStackId = proto.getStackId();
+ mType = proto.getAttributes().getType();
+ WindowStateAnimatorProto animatorProto = proto.getAnimator();
+ if (animatorProto.hasSurface()) {
+ WindowSurfaceControllerProto surfaceProto = animatorProto.getSurface();
+ mShown = surfaceProto.getShown();
+ mLayer = surfaceProto.getLayer();
+ }
+ mGivenContentInsets = extractBounds(proto.getGivenContentInsets());
+ mFrame = extractBounds(proto.getFrame());
+ mContainingFrame = extractBounds(proto.getContainingFrame());
+ mParentFrame = extractBounds(proto.getParentFrame());
+ mContentFrame = extractBounds(proto.getContentFrame());
+ mContentInsets = extractBounds(proto.getContentInsets());
+ mSurfaceInsets = extractBounds(proto.getSurfaceInsets());
+ mCrop = extractBounds(animatorProto.getLastClipRect());
+ if (mName.startsWith(STARTING_WINDOW_PREFIX)) {
+ mWindowType = WINDOW_TYPE_STARTING;
+ // Existing code depends on the prefix being removed
+ mName = mName.substring(STARTING_WINDOW_PREFIX.length());
+ } else if (proto.getAnimatingExit()) {
+ mWindowType = WINDOW_TYPE_EXITING;
+ } else if (mName.startsWith(DEBUGGER_WINDOW_PREFIX)) {
+ mWindowType = WINDOW_TYPE_STARTING;
+ mName = mName.substring(DEBUGGER_WINDOW_PREFIX.length());
+ } else {
+ mWindowType = 0;
+ }
+ for (int i = 0; i < proto.getChildWindowsCount(); i++) {
+ WindowStateProto childProto = proto.getChildWindows(i);
+ WindowState childWindow = new WindowState(childProto);
+ mSubWindows.add(childWindow);
+ mSubWindows.addAll(childWindow.getWindows());
+ }
}
public String getName() {
@@ -1026,109 +700,6 @@
return mType;
}
- static WindowState create(LinkedList<String> dump, Pattern[] exitPatterns) {
- final String line = dump.peek().trim();
-
- Matcher matcher = sWindowPattern.matcher(line);
- if (!matcher.matches()) {
- return null;
- }
-
- log(TAG + "WINDOW: " + line);
- dump.pop();
-
- final WindowState window;
- Matcher specialMatcher;
- if ((specialMatcher = sStartingWindowPattern.matcher(line)).matches()) {
- log(TAG + "STARTING: " + line);
- window = new WindowState(specialMatcher, WINDOW_TYPE_STARTING);
- } else if ((specialMatcher = sExitingWindowPattern.matcher(line)).matches()) {
- log(TAG + "EXITING: " + line);
- window = new WindowState(specialMatcher, WINDOW_TYPE_EXITING);
- } else if ((specialMatcher = sDebuggerWindowPattern.matcher(line)).matches()) {
- log(TAG + "DEBUGGER: " + line);
- window = new WindowState(specialMatcher, WINDOW_TYPE_DEBUGGER);
- } else {
- window = new WindowState(matcher, WINDOW_TYPE_NORMAL);
- }
-
- window.extract(dump, exitPatterns);
- return window;
- }
-
- private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
- while (!doneExtracting(dump, exitPatterns)) {
- final String line = dump.pop().trim();
-
- Matcher matcher = sWindowAssociationPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "WINDOW_ASSOCIATION: " + line);
- mDisplayId = Integer.valueOf(matcher.group(1));
- mStackId = Integer.valueOf(matcher.group(2));
- continue;
- }
-
- matcher = sMainFramePattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "MAIN WINDOW FRAME: " + line);
- mFrame = extractBounds(matcher);
- continue;
- }
-
- matcher = sFramePattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "FRAME: " + line);
- extractMultipleBounds(matcher, 1, mContainingFrame, mParentFrame);
- continue;
- }
-
- matcher = sContentFramePattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "CONTENT FRAME: " + line);
- mContentFrame = extractBounds(matcher);
- }
-
- matcher = sSurfaceInsetsPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "INSETS: " + line);
- mSurfaceInsets = extractBounds(matcher);
- }
-
- matcher = sContentInsetsPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "CONTENT INSETS: " + line);
- mContentInsets = extractBounds(matcher);
- }
-
- matcher = sCropPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "CROP: " + line);
- mCrop = extractBounds(matcher);
- }
-
- matcher = sSurfacePattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "SURFACE: " + line);
- mShown = Boolean.valueOf(matcher.group(1));
- mLayer = Integer.valueOf(matcher.group(2));
- }
-
- matcher = sAttrsPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "ATTRS: " + line);
- mType = Integer.valueOf(matcher.group(1));
- }
-
- matcher = sGivenContentInsetsPattern.matcher(line);
- if (matcher.matches()) {
- log(TAG + "GIVEN CONTENT INSETS: " + line);
- mGivenContentInsets = extractBounds(matcher);
- }
-
- // Extract other info here if needed
- }
- }
-
private static String getWindowTypeSuffix(int windowType) {
switch (windowType) {
case WINDOW_TYPE_STARTING: return " STARTING";
diff --git a/tests/AlarmManager/Android.mk b/tests/AlarmManager/Android.mk
new file mode 100755
index 0000000..a1676ab
--- /dev/null
+++ b/tests/AlarmManager/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES += $(call all-java-files-under, app/src)
+
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_PACKAGE_NAME := CtsAlarmManagerTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/AlarmManager/AndroidManifest.xml b/tests/AlarmManager/AndroidManifest.xml
new file mode 100644
index 0000000..f557b51
--- /dev/null
+++ b/tests/AlarmManager/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.alarmmanager.cts" >
+
+ <application android:label="Cts Alarm Manager Test">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:functionalTest="true"
+ android:targetPackage="android.alarmmanager.cts"
+ android:label="Alarm Manager Tests"/>
+</manifest>
diff --git a/tests/AlarmManager/AndroidTest.xml b/tests/AlarmManager/AndroidTest.xml
new file mode 100644
index 0000000..a31e6da
--- /dev/null
+++ b/tests/AlarmManager/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Config for CTS Alarm Manager test cases">
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsAlarmManagerTestCases.apk" />
+ <option name="test-file-name" value="AlarmTestApp.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.alarmmanager.cts" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+
+</configuration>
diff --git a/tests/AlarmManager/app/Android.mk b/tests/AlarmManager/app/Android.mk
new file mode 100644
index 0000000..b2023e9
--- /dev/null
+++ b/tests/AlarmManager/app/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AlarmTestApp
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/AlarmManager/app/AndroidManifest.xml b/tests/AlarmManager/app/AndroidManifest.xml
new file mode 100644
index 0000000..ceb8fb9
--- /dev/null
+++ b/tests/AlarmManager/app/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.alarmmanager.alarmtestapp.cts">
+
+ <application>
+ <activity android:name=".TestAlarmActivity"
+ android:exported="true" />
+ <receiver android:name=".TestAlarmReceiver" />
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java
new file mode 100644
index 0000000..25efc2c
--- /dev/null
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.alarmtestapp.cts;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * This Activity is to be used as part of {@link com.android.server.BackgroundRestrictedAlarmsTest}
+ */
+public class TestAlarmActivity extends Activity {
+ private static final String TAG = TestAlarmActivity.class.getSimpleName();
+ private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts";
+
+ public static final String ACTION_SET_ALARM = PACKAGE_NAME + ".action.SET_ALARM";
+ public static final String EXTRA_TRIGGER_TIME = PACKAGE_NAME + ".extra.TRIGGER_TIME";
+ public static final String EXTRA_REPEAT_INTERVAL = PACKAGE_NAME + ".extra.REPEAT_INTERVAL";
+ public static final String EXTRA_TYPE = PACKAGE_NAME + ".extra.TYPE";
+ public static final String ACTION_SET_ALARM_CLOCK = PACKAGE_NAME + ".action.SET_ALARM_CLOCK";
+ public static final String EXTRA_ALARM_CLOCK_INFO = PACKAGE_NAME + ".extra.ALARM_CLOCK_INFO";
+ public static final String ACTION_CANCEL_ALL_ALARMS = PACKAGE_NAME + ".action.CANCEL_ALARMS";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final AlarmManager am = getSystemService(AlarmManager.class);
+ final Intent intent = getIntent();
+ final Intent receiverIntent = new Intent(this, TestAlarmReceiver.class);
+ final PendingIntent alarmClockSender =
+ PendingIntent.getBroadcast(this, 0, receiverIntent, 0);
+ final PendingIntent alarmSender = PendingIntent.getBroadcast(this, 1, receiverIntent, 0);
+ switch (intent.getAction()) {
+ case ACTION_SET_ALARM_CLOCK:
+ if (!intent.hasExtra(EXTRA_ALARM_CLOCK_INFO)) {
+ Log.e(TAG, "No alarm clock supplied");
+ break;
+ }
+ final AlarmManager.AlarmClockInfo alarmClockInfo =
+ intent.getParcelableExtra(EXTRA_ALARM_CLOCK_INFO);
+ Log.d(TAG, "Setting alarm clock " + alarmClockInfo);
+ am.setAlarmClock(alarmClockInfo, alarmClockSender);
+ break;
+ case ACTION_SET_ALARM:
+ if (!intent.hasExtra(EXTRA_TYPE) || !intent.hasExtra(EXTRA_TRIGGER_TIME)) {
+ Log.e(TAG, "Alarm type or trigger time not supplied");
+ break;
+ }
+ final int type = intent.getIntExtra(EXTRA_TYPE, 0);
+ final long triggerTime = intent.getLongExtra(EXTRA_TRIGGER_TIME, 0);
+ final long interval = intent.getLongExtra(EXTRA_REPEAT_INTERVAL, 0);
+ Log.d(TAG, "Setting alarm: type=" + type + ", triggerTime=" + triggerTime
+ + ", interval=" + interval);
+ if (interval > 0) {
+ am.setRepeating(type, triggerTime, interval, alarmSender);
+ } else {
+ am.setExact(type, triggerTime, alarmSender);
+ }
+ break;
+ case ACTION_CANCEL_ALL_ALARMS:
+ Log.d(TAG, "Cancelling all alarms");
+ am.cancel(alarmClockSender);
+ am.cancel(alarmSender);
+ break;
+ default:
+ Log.e(TAG, "Unspecified action " + intent.getAction());
+ break;
+ }
+ finish();
+ }
+}
\ No newline at end of file
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
new file mode 100644
index 0000000..a083e08
--- /dev/null
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.alarmtestapp.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class TestAlarmReceiver extends BroadcastReceiver{
+ private static final String TAG = TestAlarmReceiver.class.getSimpleName();
+ private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts";
+ public static final String ACTION_REPORT_ALARM_EXPIRED = PACKAGE_NAME + ".action.ALARM_EXPIRED";
+ public static final String EXTRA_ALARM_COUNT = PACKAGE_NAME + ".extra.ALARM_COUNT";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int count = intent.getIntExtra(Intent.EXTRA_ALARM_COUNT, 1);
+ Log.d(TAG, "Alarm expired " + count + " times");
+ final Intent reportAlarmIntent = new Intent(ACTION_REPORT_ALARM_EXPIRED);
+ reportAlarmIntent.putExtra(EXTRA_ALARM_COUNT, count);
+ reportAlarmIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ context.sendBroadcast(reportAlarmIntent);
+ }
+}
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
new file mode 100644
index 0000000..0d6445e
--- /dev/null
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.alarmmanager.alarmtestapp.cts.TestAlarmActivity;
+import android.alarmmanager.alarmtestapp.cts.TestAlarmReceiver;
+import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BackgroundRestrictedAlarmsTest {
+ private static final String TAG = BackgroundRestrictedAlarmsTest.class.getSimpleName();
+ private static final String TEST_APP_PACKAGE = "android.alarmmanager.alarmtestapp.cts";
+ private static final String TEST_APP_ACTIVITY = TEST_APP_PACKAGE + ".TestAlarmActivity";
+ private static final String APP_OP_RUN_ANY_IN_BACKGROUND = "RUN_ANY_IN_BACKGROUND";
+ private static final String APP_OP_MODE_ALLOWED = "allow";
+ private static final String APP_OP_MODE_IGNORED = "ignore";
+
+ private static final long DEFAULT_WAIT = 1_000;
+ private static final long POLL_INTERVAL = 1_000;
+ private static final long MIN_REPEATING_INTERVAL = 10_000;
+
+ private Object mLock = new Object();
+ private Context mContext;
+ private ComponentName mAlarmActivity;
+ private UiDevice mUiDevice;
+ private int mAlarmCount;
+
+ private final BroadcastReceiver mAlarmStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Received action " + intent.getAction()
+ + " elapsed: " + SystemClock.elapsedRealtime());
+ synchronized (mLock) {
+ mAlarmCount = intent.getIntExtra(TestAlarmReceiver.EXTRA_ALARM_COUNT, 1);
+ }
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mAlarmActivity = new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY);
+ mAlarmCount = 0;
+ updateAlarmManagerConstants();
+ setAppOpsMode(APP_OP_MODE_IGNORED);
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TestAlarmReceiver.ACTION_REPORT_ALARM_EXPIRED);
+ mContext.registerReceiver(mAlarmStateReceiver, intentFilter);
+ }
+
+ private void scheduleAlarm(int type, long triggerMillis, long interval) {
+ final Intent setAlarmIntent = new Intent(TestAlarmActivity.ACTION_SET_ALARM);
+ setAlarmIntent.setComponent(mAlarmActivity);
+ setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_TYPE, type);
+ setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_TRIGGER_TIME, triggerMillis);
+ setAlarmIntent.putExtra(TestAlarmActivity.EXTRA_REPEAT_INTERVAL, interval);
+ setAlarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(setAlarmIntent);
+ }
+
+ private void scheduleAlarmClock(long triggerRTC) {
+ AlarmManager.AlarmClockInfo alarmInfo = new AlarmManager.AlarmClockInfo(triggerRTC, null);
+
+ final Intent setAlarmClockIntent = new Intent(TestAlarmActivity.ACTION_SET_ALARM_CLOCK);
+ setAlarmClockIntent.setComponent(mAlarmActivity);
+ setAlarmClockIntent.putExtra(TestAlarmActivity.EXTRA_ALARM_CLOCK_INFO, alarmInfo);
+ setAlarmClockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(setAlarmClockIntent);
+ }
+
+ private static int getMinExpectedExpirations(long now, long start, long interval) {
+ if (now - start <= 1000) {
+ return 0;
+ }
+ return 1 + (int)((now - start - 1000)/interval);
+ }
+
+ @Test
+ public void testRepeatingAlarmBlocked() throws Exception {
+ final long interval = MIN_REPEATING_INTERVAL;
+ final long triggerElapsed = SystemClock.elapsedRealtime() + interval;
+ scheduleAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed, interval);
+ Thread.sleep(DEFAULT_WAIT);
+ makeTestPackageIdle();
+ Thread.sleep(2 * interval);
+ assertFalse("Alarm got triggered even under restrictions", waitForAlarms(1, DEFAULT_WAIT));
+ Thread.sleep(interval);
+ setAppOpsMode(APP_OP_MODE_ALLOWED);
+ // The alarm is due to go off about 3 times by now. Adding some tolerance just in case
+ // an expiration is due right about now.
+ final int minCount = getMinExpectedExpirations(SystemClock.elapsedRealtime(),
+ triggerElapsed, interval);
+ assertTrue("Alarm should have expired at least " + minCount
+ + " times when restrictions were lifted", waitForAlarms(minCount, DEFAULT_WAIT));
+ }
+
+ @Test
+ public void testAlarmClockNotBlocked() throws Exception {
+ final long nowRTC = System.currentTimeMillis();
+ final long waitInterval = 10_000;
+ final long triggerRTC = nowRTC + waitInterval;
+ scheduleAlarmClock(triggerRTC);
+ Thread.sleep(waitInterval);
+ assertTrue("AlarmClock did not go off as scheduled when under restrictions",
+ waitForAlarms(1, DEFAULT_WAIT));
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ deleteAlarmManagerConstants();
+ setAppOpsMode(APP_OP_MODE_ALLOWED);
+ // Cancel any leftover alarms
+ final Intent cancelAlarmsIntent = new Intent(TestAlarmActivity.ACTION_CANCEL_ALL_ALARMS);
+ cancelAlarmsIntent.setComponent(mAlarmActivity);
+ cancelAlarmsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(cancelAlarmsIntent);
+ mContext.unregisterReceiver(mAlarmStateReceiver);
+ // Broadcast unregister may race with the next register in setUp
+ Thread.sleep(DEFAULT_WAIT);
+ }
+
+ private void updateAlarmManagerConstants() throws IOException {
+ String cmd = "settings put global alarm_manager_constants min_interval="
+ + MIN_REPEATING_INTERVAL + ",limit_bg_alarms_enabled=true";
+ mUiDevice.executeShellCommand(cmd);
+ }
+
+ private void deleteAlarmManagerConstants() throws IOException {
+ mUiDevice.executeShellCommand("settings delete global alarm_manager_constants");
+ }
+
+ private void setAppOpsMode(String mode) throws IOException {
+ StringBuilder commandBuilder = new StringBuilder("appops set ")
+ .append(TEST_APP_PACKAGE)
+ .append(" ")
+ .append(APP_OP_RUN_ANY_IN_BACKGROUND)
+ .append(" ")
+ .append(mode);
+ mUiDevice.executeShellCommand(commandBuilder.toString());
+ }
+
+ private void makeTestPackageIdle() throws IOException {
+ StringBuilder commandBuilder = new StringBuilder("am make-uid-idle --user current ")
+ .append(TEST_APP_PACKAGE);
+ mUiDevice.executeShellCommand(commandBuilder.toString());
+ }
+
+ private boolean waitForAlarms(int expectedAlarms, long timeout) throws InterruptedException {
+ final long deadLine = SystemClock.uptimeMillis() + timeout;
+ int alarmCount;
+ do {
+ Thread.sleep(POLL_INTERVAL);
+ synchronized (mLock) {
+ alarmCount = mAlarmCount;
+ }
+ } while (alarmCount < expectedAlarms && SystemClock.uptimeMillis() < deadLine);
+ return alarmCount >= expectedAlarms;
+ }
+}
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
index aa9db4f..c4d1dda 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityEventTest.java
@@ -32,7 +32,7 @@
public class AccessibilityEventTest extends TestCase {
/** The number of properties of the {@link AccessibilityEvent} class. */
- private static final int NON_STATIC_FIELD_COUNT = 29;
+ private static final int NON_STATIC_FIELD_COUNT = 31;
/**
* Test that no new fields have been added without updating the
@@ -206,6 +206,8 @@
sentEvent.setMaxScrollY(1);
sentEvent.setScrollX(1);
sentEvent.setScrollY(1);
+ sentEvent.setScrollDeltaX(3);
+ sentEvent.setScrollDeltaY(3);
sentEvent.setToIndex(1);
sentEvent.setScrollable(true);
sentEvent.setAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
@@ -261,6 +263,10 @@
receivedEvent.getScrollX());
assertSame("scrollY has incorect value", expectedEvent.getScrollY(),
receivedEvent.getScrollY());
+ assertSame("scrollDeltaX has incorect value", expectedEvent.getScrollDeltaX(),
+ receivedEvent.getScrollDeltaX());
+ assertSame("scrollDeltaY has incorect value", expectedEvent.getScrollDeltaY(),
+ receivedEvent.getScrollDeltaY());
assertSame("toIndex has incorect value", expectedEvent.getToIndex(),
receivedEvent.getToIndex());
assertSame("scrollable has incorect value", expectedEvent.isScrollable(),
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index 7862cb4..5bf02c8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -35,7 +35,7 @@
public class AccessibilityRecordTest extends AndroidTestCase {
/** The number of properties of the {@link AccessibilityEvent} class. */
- private static final int NON_STATIC_FIELD_COUNT = 22;
+ private static final int NON_STATIC_FIELD_COUNT = 24;
/**
* Test that no new fields have been added without updating the
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
index b67fc28..8b1154e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
@@ -63,16 +63,22 @@
if (mSingleVolume) {
return;
}
- int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
- int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
- InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
- mInstrumentation, InstrumentedAccessibilityService.class);
-
- service.runOnServiceSync(() ->
- mAudioManager.setStreamVolume(AudioManager.STREAM_ACCESSIBILITY, otherVolume, 0));
- assertEquals("Accessibility service should be able to change accessibility volume",
- otherVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY));
- service.runOnServiceSync(() -> mAudioManager.setStreamVolume(
- AudioManager.STREAM_ACCESSIBILITY, startingVolume, 0));
+ final int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
+ final int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
+ final InstrumentedAccessibilityService service = InstrumentedAccessibilityService
+ .enableService(mInstrumentation, InstrumentedAccessibilityService.class);
+ try {
+ service.runOnServiceSync(() ->
+ mAudioManager.setStreamVolume(AudioManager.STREAM_ACCESSIBILITY, otherVolume,
+ 0));
+ assertEquals("Accessibility service should be able to change accessibility volume",
+ otherVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY));
+ service.runOnServiceSync(() -> mAudioManager.setStreamVolume(
+ AudioManager.STREAM_ACCESSIBILITY, startingVolume, 0));
+ } finally {
+ if (service != null) {
+ service.runOnServiceSync(() -> service.disableSelf());
+ }
+ }
}
}
diff --git a/tests/app/src/android/app/cts/NotificationChannelGroupTest.java b/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
index 162815f..7931a1f 100644
--- a/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelGroupTest.java
@@ -37,10 +37,21 @@
NotificationChannelGroup group = new NotificationChannelGroup("1", "one");
assertEquals("1", group.getId());
assertEquals("one", group.getName());
+ assertFalse(group.isBlocked());
+ assertNull(group.getDescription());
+ assertEquals(0, group.getChannels().size());
+ }
+
+ public void testIsBlocked() {
+ NotificationChannelGroup group = new NotificationChannelGroup("1", "one");
+ group.setBlocked(true);
+ assertTrue(group.isBlocked());
}
public void testWriteToParcel() {
NotificationChannelGroup group = new NotificationChannelGroup("1", "one");
+ group.setBlocked(true);
+ group.setDescription("bananas!");
Parcel parcel = Parcel.obtain();
group.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
@@ -51,8 +62,12 @@
public void testClone() {
NotificationChannelGroup group = new NotificationChannelGroup("1", "one");
+ group.setBlocked(true);
+ group.setDescription("bananas");
NotificationChannelGroup cloned = group.clone();
assertEquals("1", cloned.getId());
assertEquals("one", cloned.getName());
+ assertTrue(cloned.isBlocked());
+ assertEquals("bananas", cloned.getDescription());
}
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index b6077ca..a4480f8 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -80,6 +80,12 @@
}
mNotificationManager.deleteNotificationChannel(nc.getId());
}
+
+ List<NotificationChannelGroup> groups = mNotificationManager.getNotificationChannelGroups();
+ // Delete all groups.
+ for (NotificationChannelGroup ncg : groups) {
+ mNotificationManager.deleteNotificationChannelGroup(ncg.getId());
+ }
}
public void testCreateChannelGroup() throws Exception {
@@ -151,6 +157,46 @@
mNotificationManager.getNotificationChannel(mId).getImportance());
}
+ public void testCreateChannel_addToGroup() throws Exception {
+ String oldGroup = null;
+ String newGroup = "new group";
+ mNotificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(newGroup, newGroup));
+
+ NotificationChannel channel =
+ new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setGroup(oldGroup);
+ mNotificationManager.createNotificationChannel(channel);
+
+ channel.setGroup(newGroup);
+ mNotificationManager.createNotificationChannel(channel);
+
+ final NotificationChannel updatedChannel =
+ mNotificationManager.getNotificationChannel(mId);
+ assertEquals("Failed to add non-grouped channel to a group on update ",
+ newGroup, updatedChannel.getGroup());
+ }
+
+ public void testCreateChannel_cannotChangeGroup() throws Exception {
+ String oldGroup = "old group";
+ String newGroup = "new group";
+ mNotificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(oldGroup, oldGroup));
+ mNotificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(newGroup, newGroup));
+
+ NotificationChannel channel =
+ new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setGroup(oldGroup);
+ mNotificationManager.createNotificationChannel(channel);
+ channel.setGroup(newGroup);
+ mNotificationManager.createNotificationChannel(channel);
+ final NotificationChannel updatedChannel =
+ mNotificationManager.getNotificationChannel(mId);
+ assertEquals("Channels should not be allowed to change groups",
+ oldGroup, updatedChannel.getGroup());
+ }
+
public void testCreateSameChannelDoesNotUpdate() throws Exception {
final NotificationChannel channel =
new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -328,6 +374,54 @@
}
}
+ public void testNotify_blockedChannel() throws Exception {
+ mNotificationManager.cancelAll();
+
+ NotificationChannel channel =
+ new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_NONE);
+ mNotificationManager.createNotificationChannel(channel);
+
+ int id = 1;
+ final Notification notification =
+ new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.black)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("notify#" + id)
+ .setContentText("This is #" + id + "notification ")
+ .build();
+ mNotificationManager.notify(id, notification);
+
+ if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+ fail("found unexpected notification id=" + id);
+ }
+ }
+
+ public void testNotify_blockedChannelGroup() throws Exception {
+ mNotificationManager.cancelAll();
+
+ NotificationChannelGroup group = new NotificationChannelGroup(mId, "group name");
+ group.setBlocked(true);
+ mNotificationManager.createNotificationChannelGroup(group);
+ NotificationChannel channel =
+ new NotificationChannel(mId, "name", NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setGroup(mId);
+ mNotificationManager.createNotificationChannel(channel);
+
+ int id = 1;
+ final Notification notification =
+ new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.black)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("notify#" + id)
+ .setContentText("This is #" + id + "notification ")
+ .build();
+ mNotificationManager.notify(id, notification);
+
+ if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+ fail("found unexpected notification id=" + id);
+ }
+ }
+
public void testCancel() throws Exception {
final int id = 9;
sendNotification(id, R.drawable.black);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 206f180..273d150 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -2744,6 +2744,8 @@
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_AUTHENTICATION_SELECTED);
assertThat(event.getDatasetId()).isEqualTo("name");
+ assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
});
}
@@ -2788,6 +2790,8 @@
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_AUTHENTICATION_SELECTED);
assertThat(event.getDatasetId()).isNull();
+ assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "clientStateValue");
});
}
@@ -2796,11 +2800,15 @@
enableService();
// Set up first partition with an anonymous dataset
+ Bundle clientState1 = new Bundle();
+ clientState1.putCharSequence("clientStateKey", "Value1");
+
sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
new CannedDataset.Builder()
.setField(ID_USERNAME, "username")
.setPresentation(createPresentation("dataset1"))
.build())
+ .setExtras(clientState1)
.build());
// Trigger autofill on username
@@ -2812,17 +2820,20 @@
// Verify fill selection
FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
.getFillEventHistory();
- assertThat(selection.getClientState()).isNull();
+ assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "Value1");
assertThat(selection.getEvents().size()).isEqualTo(1);
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event.getDatasetId()).isNull();
+ assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "Value1");
});
// Set up second partition with a named dataset
- Bundle clientState = new Bundle();
- clientState.putCharSequence("clientStateKey", "clientStateValue");
+ Bundle clientState2 = new Bundle();
+ clientState2.putCharSequence("clientStateKey", "Value2");
sReplier.addResponse(new CannedFillResponse.Builder()
.addDataset(
@@ -2837,7 +2848,7 @@
.setPresentation(createPresentation("dataset3"))
.setId("name3")
.build())
- .setExtras(clientState)
+ .setExtras(clientState2)
.setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_PASSWORD).build());
// Trigger autofill on password
@@ -2850,12 +2861,14 @@
FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
.getFillEventHistory();
assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
- "clientStateValue");
+ "Value2");
assertThat(selection.getEvents().size()).isEqualTo(1);
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event.getDatasetId()).isEqualTo("name3");
+ assertThat(event.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "Value2");
});
mActivity.onPassword((v) -> v.setText("new password"));
@@ -2866,16 +2879,20 @@
FillEventHistory selection = InstrumentedAutoFillService.peekInstance()
.getFillEventHistory();
assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
- "clientStateValue");
+ "Value2");
assertThat(selection.getEvents().size()).isEqualTo(2);
FillEventHistory.Event event1 = selection.getEvents().get(0);
assertThat(event1.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event1.getDatasetId()).isEqualTo("name3");
+ assertThat(event1.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "Value2");
FillEventHistory.Event event2 = selection.getEvents().get(1);
assertThat(event2.getType()).isEqualTo(TYPE_SAVE_SHOWN);
assertThat(event2.getDatasetId()).isNull();
+ assertThat(event2.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+ "Value2");
});
}
@@ -2904,6 +2921,7 @@
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event.getDatasetId()).isNull();
+ assertThat(event.getClientState()).isNull();
});
// Second request
@@ -2946,6 +2964,7 @@
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event.getDatasetId()).isNull();
+ assertThat(event.getClientState()).isNull();
});
// Second request
@@ -2988,6 +3007,7 @@
FillEventHistory.Event event = selection.getEvents().get(0);
assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
assertThat(event.getDatasetId()).isNull();
+ assertThat(event.getClientState()).isNull();
});
// Second request
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 333045a..28745f3 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -20,6 +20,7 @@
<application>
<uses-library android:name="android.test.runner" />
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
index b89f9bb..98f1032 100644
--- a/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
+++ b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
@@ -223,7 +223,7 @@
if (other instanceof AllocationKey){
AllocationKey otherKey = (AllocationKey) other;
- return otherKey.mType.equals(mType) && otherKey.mUsage == otherKey.mUsage;
+ return otherKey.mType.equals(mType) && otherKey.mUsage == mUsage;
}
return false;
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index 834d37c..0f48364 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -227,18 +227,15 @@
verify(spyStateCb, times(1)).onOpened(any(CameraDevice.class));
// Verify that we can no longer open the camera, as it is held by a higher priority process
- boolean openException = false;
try {
manager.openCamera(chosenCamera, spyStateCb, cameraHandler);
+ fail("Didn't receive exception when trying to open camera held by higher priority " +
+ "process.");
} catch(CameraAccessException e) {
assertTrue("Received incorrect camera exception when opening camera: " + e,
e.getReason() == CameraAccessException.CAMERA_IN_USE);
- openException = true;
}
- assertTrue("Didn't receive exception when trying to open camera held by higher priority " +
- "process.", openException);
-
// Verify that attempting to open the camera didn't cause anything weird to happen in the
// other process.
List<ErrorLoggingService.LogEvent> eventList2 = null;
diff --git a/tests/core/Android.mk b/tests/core/Android.mk
index 7a2a708..e9c9793 100644
--- a/tests/core/Android.mk
+++ b/tests/core/Android.mk
@@ -14,6 +14,4 @@
LOCAL_PATH:= $(call my-dir)
-BUILD_CTSCORE_PACKAGE:=$(LOCAL_PATH)/ctscore.mk
-
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/core/ctscore.mk b/tests/core/ctscore.mk
deleted file mode 100644
index 10a91f1..0000000
--- a/tests/core/ctscore.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-# don't include these packages in any target
-LOCAL_MODULE_TAGS := optional
-# and when installed explicitly put them in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-# Don't delete META-INF from the core-tests jar
-LOCAL_DONT_DELETE_JAR_META_INF := true
-
-# TODO: Clean up this mess. (b/26483949). libnativehelper_compat_libc++ pulls in its own
-# static copy of libc++ and the libc++ we're bundling here is the platform libc++. This is
-# bround to break but is being submitted as a workaround for failing CTS tests.
-LOCAL_JNI_SHARED_LIBRARIES := libjavacoretests libsqlite_jni libnativehelper_compat_libc++ libc++
-
-# Include both the 32 and 64 bit versions of libjavacoretests,
-# where applicable.
-LOCAL_MULTILIB := both
-
-include $(BUILD_PACKAGE)
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index 7e4fb0d..f86ee2f 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -14,21 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
-include $(CLEAR_VARS)
-
-# include this package in the tests target for continuous testing
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PACKAGE_NAME := android.core.tests.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
-
-include $(BUILD_CTSCORE_PACKAGE)
-
#==========================================================
# Build the core runner.
#==========================================================
diff --git a/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java b/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java
deleted file mode 100644
index 108e8fd..0000000
--- a/tests/core/runner/src/com/android/cts/core/internal/runner/TestLoader.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * This file is a copy of https://cs.corp.google.com/android/frameworks/testing/runner/src/main/java/android/support/test/internal/runner/TestLoader.java
- * The only changes that have been made starts with // Libcore-specific
- */
-
-package com.android.cts.core.internal.runner;
-
-import android.util.Log;
-
-import org.junit.runner.Description;
-import org.junit.runner.notification.Failure;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class for loading JUnit3 and JUnit4 test classes given a set of potential class names.
- */
-public final class TestLoader {
-
- private static final String LOG_TAG = "TestLoader";
- // Libcore-specific change: Fully qualified name of TestNG annotation class.
- private static final String TESTNG_TEST = "org.testng.annotations.Test";
-
- private Map<String, Class<?>> mLoadedClassesMap = new LinkedHashMap<String, Class<?>>();
- private Map<String, Failure> mLoadFailuresMap = new LinkedHashMap<String, Failure>();
-
- private ClassLoader mClassLoader;
-
- /**
- * Set the {@link ClassLoader} to be used to load test cases.
- *
- * @param loader {@link ClassLoader} to load test cases with.
- */
- public void setClassLoader(ClassLoader loader) {
- mClassLoader = loader;
- }
-
- /**
- * Loads the test class from a given class name if its not already loaded.
- * <p/>
- * Will store the result internally. Successfully loaded classes can be retrieved via
- * {@link #getLoadedClasses()}, failures via {@link #getLoadFailures()}.
- *
- * @param className the class name to attempt to load
- * @return the loaded class or null.
- */
- public Class<?> loadClass(String className) {
- Class<?> loadedClass = doLoadClass(className);
- if (loadedClass != null) {
- mLoadedClassesMap.put(className, loadedClass);
- }
- return loadedClass;
- }
-
- protected ClassLoader getClassLoader() {
- if (mClassLoader != null) {
- return mClassLoader;
- }
-
- // TODO: InstrumentationTestRunner uses
- // Class.forName(className, false, getTargetContext().getClassLoader());
- // Evaluate if that is needed. Initial testing indicates
- // getTargetContext().getClassLoader() == this.getClass().getClassLoader()
- return this.getClass().getClassLoader();
- }
-
- private Class<?> doLoadClass(String className) {
- if (mLoadFailuresMap.containsKey(className)) {
- // Don't load classes that already failed to load
- return null;
- } else if (mLoadedClassesMap.containsKey(className)) {
- // Class with the same name was already loaded, return it
- return mLoadedClassesMap.get(className);
- }
-
- try {
- ClassLoader myClassLoader = getClassLoader();
- return Class.forName(className, false, myClassLoader);
- } catch (ClassNotFoundException e) {
- String errMsg = String.format("Could not find class: %s", className);
- Log.e(LOG_TAG, errMsg);
- Description description = Description.createSuiteDescription(className);
- Failure failure = new Failure(description, e);
- mLoadFailuresMap.put(className, failure);
- }
- return null;
- }
-
- /**
- * Loads the test class from the given class name.
- * <p/>
- * Similar to {@link #loadClass(String)}, but will ignore classes that are
- * not tests.
- *
- * @param className the class name to attempt to load
- * @return the loaded class or null.
- */
- public Class<?> loadIfTest(String className) {
- Class<?> loadedClass = doLoadClass(className);
- if (loadedClass != null && isTestClass(loadedClass)) {
- mLoadedClassesMap.put(className, loadedClass);
- return loadedClass;
- }
- return null;
- }
-
- /**
- * @return whether this {@link TestLoader} contains any loaded classes or load failures.
- */
- public boolean isEmpty() {
- return mLoadedClassesMap.isEmpty() && mLoadFailuresMap.isEmpty();
- }
-
- /**
- * Get the {@link Collection) of classes successfully loaded via
- * {@link #loadIfTest(String)} calls.
- */
- public Collection<Class<?>> getLoadedClasses() {
- return mLoadedClassesMap.values();
- }
-
- /**
- * Get the {@link List) of {@link Failure} that occurred during
- * {@link #loadIfTest(String)} calls.
- */
- public Collection<Failure> getLoadFailures() {
- return mLoadFailuresMap.values();
- }
-
- /**
- * Determines if given class is a valid test class.
- *
- * @param loadedClass
- * @return <code>true</code> if loadedClass is a test
- */
- private boolean isTestClass(Class<?> loadedClass) {
- try {
- if (Modifier.isAbstract(loadedClass.getModifiers())) {
- logDebug(String.format("Skipping abstract class %s: not a test",
- loadedClass.getName()));
- return false;
- }
- // Libcore-specific change: Also consider TestNG annotated classes.
- if (isTestNgTestClass(loadedClass)) {
- return true;
- }
- // TODO: try to find upstream junit calls to replace these checks
- if (junit.framework.Test.class.isAssignableFrom(loadedClass)) {
- // ensure that if a TestCase, it has at least one test method otherwise
- // TestSuite will throw error
- if (junit.framework.TestCase.class.isAssignableFrom(loadedClass)) {
- return hasJUnit3TestMethod(loadedClass);
- }
- return true;
- }
- // TODO: look for a 'suite' method?
- if (loadedClass.isAnnotationPresent(org.junit.runner.RunWith.class)) {
- return true;
- }
- for (Method testMethod : loadedClass.getMethods()) {
- if (testMethod.isAnnotationPresent(org.junit.Test.class)) {
- return true;
- }
- }
- logDebug(String.format("Skipping class %s: not a test", loadedClass.getName()));
- return false;
- } catch (Exception e) {
- // Defensively catch exceptions - Will throw runtime exception if it cannot load methods.
- // For earlier versions of Android (Pre-ICS), Dalvik might try to initialize a class
- // during getMethods(), fail to do so, hide the error and throw a NoSuchMethodException.
- // Since the java.lang.Class.getMethods does not declare such an exception, resort to a
- // generic catch all.
- // For ICS+, Dalvik will throw a NoClassDefFoundException.
- Log.w(LOG_TAG, String.format("%s in isTestClass for %s", e.toString(),
- loadedClass.getName()));
- return false;
- } catch (Error e) {
- // defensively catch Errors too
- Log.w(LOG_TAG, String.format("%s in isTestClass for %s", e.toString(),
- loadedClass.getName()));
- return false;
- }
- }
-
- private boolean hasJUnit3TestMethod(Class<?> loadedClass) {
- for (Method testMethod : loadedClass.getMethods()) {
- if (isPublicTestMethod(testMethod)) {
- return true;
- }
- }
- return false;
- }
-
- // copied from junit.framework.TestSuite
- private boolean isPublicTestMethod(Method m) {
- return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
- }
-
- // copied from junit.framework.TestSuite
- private boolean isTestMethod(Method m) {
- return m.getParameterTypes().length == 0 && m.getName().startsWith("test")
- && m.getReturnType().equals(Void.TYPE);
- }
-
- // Libcore-specific change: Add method for checking TestNG-annotated classes.
- private static boolean isTestNgTestClass(Class<?> cls) {
- // TestNG test is either marked @Test at the class
- for (Annotation a : cls.getAnnotations()) {
- if (a.annotationType().getName().equals(TESTNG_TEST)) {
- return true;
- }
- }
-
- // Or It's marked @Test at the method level
- for (Method m : cls.getDeclaredMethods()) {
- for (Annotation a : m.getAnnotations()) {
- if (a.annotationType().getName().equals(TESTNG_TEST)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
-
- /**
- * Utility method for logging debug messages. Only actually logs a message if LOG_TAG is marked
- * as loggable to limit log spam during normal use.
- */
- private void logDebug(String msg) {
- if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
- Log.d(LOG_TAG, msg);
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
deleted file mode 100644
index 4b18cdc..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner;
-
-import android.support.test.runner.AndroidJUnitRunner;
-
-/**
- * Constants used to communicate to and from {@link AndroidJUnitRunner}.
- */
-public interface AndroidJUnitRunnerConstants {
-
- /**
- * The name of the file containing the names of the tests to run.
- *
- * <p>This is an internal constant used within
- * {@code android.support.test.internal.runner.RunnerArgs}, which is used on both the server
- * and
- * client side. The constant is used when there are too many test names to pass on the command
- * line, in which case they are stored in a file that is pushed to the device and then the
- * location of that file is passed in this argument. The {@code RunnerArgs} on the client will
- * read the contents of that file in order to retrieve the list of names and then return that
- * to
- * its client without the client being aware of how that was done.
- */
- String ARGUMENT_TEST_FILE = "testFile";
-
- /**
- * The name of the file containing the names of the tests not to run.
- *
- * <p>This is an internal constant used within
- * {@code android.support.test.internal.runner.RunnerArgs}, which is used on both the server
- * and
- * client side. The constant is used when there are too many test names to pass on the command
- * line, in which case they are stored in a file that is pushed to the device and then the
- * location of that file is passed in this argument. The {@code RunnerArgs} on the client will
- * read the contents of that file in order to retrieve the list of names and then return that
- * to
- * its client without the client being aware of how that was done.
- */
- String ARGUMENT_NOT_TEST_FILE = "notTestFile";
-
- /**
- * A comma separated list of the names of test classes to run.
- *
- * <p>The equivalent constant in {@code InstrumentationTestRunner} is hidden and so not
- * available
- * through the public API.
- */
- String ARGUMENT_TEST_CLASS = "class";
-
- /**
- * A comma separated list of the names of test classes not to run
- */
- String ARGUMENT_NOT_TEST_CLASS = "notClass";
-
- /**
- * A comma separated list of the names of test packages to run.
- *
- * <p>The equivalent constant in {@code InstrumentationTestRunner} is hidden and so not
- * available
- * through the public API.
- */
- String ARGUMENT_TEST_PACKAGE = "package";
-
- /**
- * A comma separated list of the names of test packages not to run.
- */
- String ARGUMENT_NOT_TEST_PACKAGE = "notPackage";
-
- /**
- * Log the results as if the tests were executed but don't actually run the tests.
- *
- * <p>The equivalent constant in {@code InstrumentationTestRunner} is private.
- */
- String ARGUMENT_LOG_ONLY = "log";
-
- /**
- * Wait for the debugger before starting.
- *
- * <p>There is no equivalent constant in {@code InstrumentationTestRunner} but the string is
- * used
- * within that class.
- */
- String ARGUMENT_DEBUG = "debug";
-
- /**
- * Only count the number of tests to run.
- *
- * <p>There is no equivalent constant in {@code InstrumentationTestRunner} but the string is
- * used
- * within that class.
- */
- String ARGUMENT_COUNT = "count";
-
- /**
- * The per test timeout value.
- */
- String ARGUMENT_TIMEOUT = "timeout_msec";
-
- /**
- * Token representing how long (in seconds) the current test took to execute.
- *
- * <p>The equivalent constant in {@code InstrumentationTestRunner} is private.
- */
- String REPORT_KEY_RUNTIME = "runtime";
-
- /**
- * An identifier for tests run using this class.
- */
- String REPORT_VALUE_ID = "CoreTestRunner";
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
deleted file mode 100644
index 42b6684..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.os.Bundle;
-import android.os.Debug;
-import android.support.test.internal.runner.listener.InstrumentationResultPrinter;
-import android.support.test.internal.runner.listener.InstrumentationRunListener;
-import android.support.test.internal.util.AndroidRunnerParams;
-import android.util.Log;
-import com.android.cts.core.runner.support.ExtendedAndroidRunnerBuilder;
-import com.google.common.base.Splitter;
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.junit.runner.Computer;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Request;
-import org.junit.runner.Result;
-import org.junit.runner.Runner;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.Filterable;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.notification.RunListener;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.RunnerBuilder;
-
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_CLASS;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_FILE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_NOT_TEST_PACKAGE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_PACKAGE;
-import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TIMEOUT;
-
-/**
- * A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
- * similar functionality, but can filter by expectations and allows a custom runner-builder to be
- * provided.
- */
-public class CoreTestRunner extends Instrumentation {
-
- static final String TAG = "LibcoreTestRunner";
-
- private static final java.lang.String ARGUMENT_ROOT_CLASSES = "core-root-classes";
-
- private static final String ARGUMENT_CORE_LISTENER = "core-listener";
-
- private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
-
- /** The args for the runner. */
- private Bundle args;
-
- /** Only log the number and names of tests, and not run them. */
- private boolean logOnly;
-
- /** The amount of time in millis to wait for a single test to complete. */
- private long testTimeout;
-
- /**
- * The list of tests to run.
- */
- private TestList testList;
-
- /**
- * The list of {@link RunListener} classes to create.
- */
- private List<Class<? extends RunListener>> listenerClasses;
- private Filter expectationFilter;
-
- @Override
- public void onCreate(final Bundle args) {
- super.onCreate(args);
- this.args = args;
-
- boolean debug = "true".equalsIgnoreCase(args.getString(ARGUMENT_DEBUG));
- if (debug) {
- Log.i(TAG, "Waiting for debugger to connect...");
- Debug.waitForDebugger();
- Log.i(TAG, "Debugger connected.");
- }
-
- // Log the message only after getting a value from the args so that the args are
- // unparceled.
- Log.d(TAG, "In OnCreate: " + args);
-
- // Treat logOnly and count as the same. This is not quite true as count should only send
- // the host the number of tests but logOnly should send the name and number. However,
- // this is how this has always behaved and it does not appear to have caused any problems.
- // Changing it seems unnecessary given that count is CTSv1 only and CTSv1 will be removed
- // soon now that CTSv2 is ready.
- boolean testCountOnly = args.getBoolean(ARGUMENT_COUNT);
- this.logOnly = "true".equalsIgnoreCase(args.getString(ARGUMENT_LOG_ONLY)) || testCountOnly;
- this.testTimeout = parseUnsignedLong(args.getString(ARGUMENT_TIMEOUT), ARGUMENT_TIMEOUT);
-
- expectationFilter = new ExpectationBasedFilter(args);
-
- // The test can be run specifying a list of tests to run, or as cts-tradefed does it,
- // by passing a fileName with a test to run on each line.
- Set<String> testNameSet = new HashSet<>();
- String arg;
- if ((arg = args.getString(ARGUMENT_TEST_FILE)) != null) {
- // The tests are specified in a file.
- try {
- testNameSet.addAll(readTestsFromFile(arg));
- } catch (IOException err) {
- finish(Activity.RESULT_CANCELED, new Bundle());
- return;
- }
- } else if ((arg = args.getString(ARGUMENT_TEST_CLASS)) != null) {
- // The tests are specified in a String passed in the bundle.
- String[] tests = arg.split(",");
- testNameSet.addAll(Arrays.asList(tests));
- }
-
- // Tests may be excluded from the run by passing a list of tests not to run,
- // or by passing a fileName with a test not to run on each line.
- Set<String> notTestNameSet = new HashSet<>();
- if ((arg = args.getString(ARGUMENT_NOT_TEST_FILE)) != null) {
- // The tests are specified in a file.
- try {
- notTestNameSet.addAll(readTestsFromFile(arg));
- } catch (IOException err) {
- finish(Activity.RESULT_CANCELED, new Bundle());
- return;
- }
- } else if ((arg = args.getString(ARGUMENT_NOT_TEST_CLASS)) != null) {
- // The classes are specified in a String passed in the bundle
- String[] tests = arg.split(",");
- notTestNameSet.addAll(Arrays.asList(tests));
- }
-
- Set<String> packageNameSet = new HashSet<>();
- if ((arg = args.getString(ARGUMENT_TEST_PACKAGE)) != null) {
- // The packages are specified in a String passed in the bundle
- String[] packages = arg.split(",");
- packageNameSet.addAll(Arrays.asList(packages));
- }
-
- Set<String> notPackageNameSet = new HashSet<>();
- if ((arg = args.getString(ARGUMENT_NOT_TEST_PACKAGE)) != null) {
- // The packages are specified in a String passed in the bundle
- String[] packages = arg.split(",");
- notPackageNameSet.addAll(Arrays.asList(packages));
- }
-
- List<String> roots = getRootClassNames(args);
- if (roots == null) {
- // Find all test classes
- Collection<Class<?>> classes = TestClassFinder.getClasses(
- Collections.singletonList(getContext().getPackageCodePath()),
- getClass().getClassLoader());
- testList = new TestList(classes);
- } else {
- testList = TestList.rootList(roots);
- }
-
- testList.addIncludeTestPackages(packageNameSet);
- testList.addExcludeTestPackages(notPackageNameSet);
- testList.addIncludeTests(testNameSet);
- testList.addExcludeTests(notTestNameSet);
-
- listenerClasses = new ArrayList<>();
- String listenerArg = args.getString(ARGUMENT_CORE_LISTENER);
- if (listenerArg != null) {
- List<String> listenerClassNames = CLASS_LIST_SPLITTER.splitToList(listenerArg);
- for (String listenerClassName : listenerClassNames) {
- try {
- Class<? extends RunListener> listenerClass = Class.forName(listenerClassName)
- .asSubclass(RunListener.class);
- listenerClasses.add(listenerClass);
- } catch (ClassNotFoundException e) {
- Log.e(TAG, "Could not load listener class: " + listenerClassName, e);
- }
- }
- }
-
- start();
- }
-
- private List<String> getRootClassNames(Bundle args) {
- String rootClasses = args.getString(ARGUMENT_ROOT_CLASSES);
- List<String> roots;
- if (rootClasses == null) {
- roots = null;
- } else {
- roots = CLASS_LIST_SPLITTER.splitToList(rootClasses);
- }
- return roots;
- }
-
- @Override
- public void onStart() {
- if (logOnly) {
- Log.d(TAG, "Counting/logging tests only");
- } else {
- Log.d(TAG, "Running tests");
- }
-
- AndroidRunnerParams runnerParams = new AndroidRunnerParams(this, args,
- false, testTimeout, false /*ignoreSuiteMethods*/);
-
- Runner runner;
- try {
- RunnerBuilder runnerBuilder = new ExtendedAndroidRunnerBuilder(runnerParams);
- Class[] classes = testList.getClassesToRun();
- for (Class cls : classes) {
- Log.d(TAG, "Found class to run: " + cls.getName());
- }
- runner = new Computer().getSuite(runnerBuilder, classes);
-
- if (runner instanceof Filterable) {
- Log.d(TAG, "Applying filters");
- Filterable filterable = (Filterable) runner;
-
- // Filter out all the tests that are expected to fail.
- try {
- filterable.filter(expectationFilter);
- } catch (NoTestsRemainException e) {
- // Sometimes filtering will remove all tests but we do not care about that.
- }
- Log.d(TAG, "Applied filters");
- }
-
- // If the tests are only supposed to be logged and not actually run then replace the
- // runner with a runner that will fire notifications for all the tests that would have
- // been run. This is needed because CTSv2 does a log only run through a CTS module in
- // order to generate a list of tests that will be run so that it can monitor them.
- // Encapsulating that in a Runner implementation makes it easier to leverage the
- // existing code for running tests.
- if (logOnly) {
- runner = new DescriptionHierarchyNotifier(runner.getDescription());
- }
-
- } catch (InitializationError e) {
- throw new RuntimeException("Could not create a suite", e);
- }
-
- InstrumentationResultPrinter instrumentationResultPrinter =
- new InstrumentationResultPrinter();
- instrumentationResultPrinter.setInstrumentation(this);
-
- JUnitCore core = new JUnitCore();
- core.addListener(instrumentationResultPrinter);
-
- // If not logging the list of tests then add any additional configured listeners. These
- // must be added before firing any events.
- if (!logOnly) {
- // Add additional configured listeners.
- for (Class<? extends RunListener> listenerClass : listenerClasses) {
- try {
- RunListener runListener = listenerClass.newInstance();
- if (runListener instanceof InstrumentationRunListener) {
- ((InstrumentationRunListener) runListener).setInstrumentation(this);
- }
- core.addListener(runListener);
- } catch (InstantiationException | IllegalAccessException e) {
- Log.e(TAG,
- "Could not create instance of listener: " + listenerClass, e);
- }
- }
- }
-
- Log.d(TAG, "Finished preparations, running/listing tests");
-
- Bundle results = new Bundle();
- Result junitResults = new Result();
- try {
- junitResults = core.run(Request.runner(runner));
- } catch (RuntimeException e) {
- final String msg = "Fatal exception when running tests";
- Log.e(TAG, msg, e);
- // report the exception to instrumentation out
- results.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
- msg + "\n" + Log.getStackTraceString(e));
- } finally {
- ByteArrayOutputStream summaryStream = new ByteArrayOutputStream();
- // create the stream used to output summary data to the user
- PrintStream summaryWriter = new PrintStream(summaryStream);
- instrumentationResultPrinter.instrumentationRunFinished(summaryWriter,
- results, junitResults);
- summaryWriter.close();
- results.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
- String.format("\n%s", summaryStream.toString()));
- }
-
-
- Log.d(TAG, "Finished");
- finish(Activity.RESULT_OK, results);
- }
-
- /**
- * Read tests from a specified file.
- *
- * @return class names of tests. If there was an error reading the file, null is returned.
- */
- private static List<String> readTestsFromFile(String fileName) throws IOException {
- try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
- List<String> tests = new ArrayList<>();
- String line;
- while ((line = br.readLine()) != null) {
- tests.add(line);
- }
- return tests;
- } catch (IOException err) {
- Log.e(TAG, "There was an error reading the test class list: " + err.getMessage());
- throw err;
- }
- }
-
- /**
- * Parse long from given value - except either Long or String.
- *
- * @return the value, -1 if not found
- * @throws NumberFormatException if value is negative or not a number
- */
- private static long parseUnsignedLong(Object value, String name) {
- if (value != null) {
- long longValue = Long.parseLong(value.toString());
- if (longValue < 0) {
- throw new NumberFormatException(name + " can not be negative");
- }
- return longValue;
- }
- return -1;
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java b/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java
deleted file mode 100644
index 5c94fd7..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/DescriptionHierarchyNotifier.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner;
-
-import java.util.List;
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.notification.RunNotifier;
-
-/**
- * A {@link Runner} that does not actually run any tests but simply fires events for all leaf
- * {@link Description} instances in the supplied {@link Description} hierarchy.
- */
-class DescriptionHierarchyNotifier extends Runner {
-
- private final Description description;
-
- DescriptionHierarchyNotifier(Description description) {
- this.description = description;
- }
-
- @Override
- public Description getDescription() {
- return description;
- }
-
- @Override
- public void run(RunNotifier notifier) {
- generateListOfTests(notifier, description);
- }
-
- /**
- * Generates a list of tests to run by recursing over the {@link Description} hierarchy and
- * firing events to simulate the tests being run successfully.
- * @param runNotifier the notifier to which the events are sent.
- * @param description the description to traverse.
- */
- private void generateListOfTests(RunNotifier runNotifier, Description description) {
- List<Description> children = description.getChildren();
- if (children.isEmpty()) {
- runNotifier.fireTestStarted(description);
- runNotifier.fireTestFinished(description);
- } else {
- for (Description child : children) {
- generateListOfTests(runNotifier, child);
- }
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java b/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
index 90034ec..f409dbd 100644
--- a/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/ExpectationBasedFilter.java
@@ -105,7 +105,7 @@
if (expectationStore != null) {
Expectation expectation = expectationStore.get(testName);
if (expectation.getResult() != Result.SUCCESS) {
- Log.d(CoreTestRunner.TAG, "Excluding test " + testDescription
+ Log.d(TAG, "Excluding test " + testDescription
+ " as it matches expectation: " + expectation);
return false;
}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java b/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java
deleted file mode 100644
index 6ad95f6..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/TestClassFinder.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner;
-
-import android.support.test.internal.runner.ClassPathScanner;
-import android.support.test.internal.runner.ClassPathScanner.ClassNameFilter;
-import android.util.Log;
-
-import com.android.cts.core.internal.runner.TestLoader;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Set;
-
-import dalvik.system.DexFile;
-
-/**
- * Find tests in the current APK.
- */
-public class TestClassFinder {
-
- private static final String TAG = "TestClassFinder";
- private static final boolean DEBUG = false;
-
- // Excluded test packages
- private static final String[] DEFAULT_EXCLUDED_PACKAGES = {
- "junit",
- "org.junit",
- "org.hamcrest",
- "org.mockito",// exclude Mockito for performance and to prevent JVM related errors
- "android.support.test.internal.runner.junit3",// always skip AndroidTestSuite
- };
-
- static Collection<Class<?>> getClasses(List<String> apks, ClassLoader loader) {
- if (DEBUG) {
- Log.d(TAG, "getClasses: =======================================");
-
- for (String apkPath : apks) {
- Log.d(TAG, "getClasses: -------------------------------");
- Log.d(TAG, "getClasses: APK " + apkPath);
-
- DexFile dexFile = null;
- try {
- dexFile = new DexFile(apkPath);
- Enumeration<String> apkClassNames = dexFile.entries();
- while (apkClassNames.hasMoreElements()) {
- String apkClassName = apkClassNames.nextElement();
- Log.d(TAG, "getClasses: DexClass element " + apkClassName);
- }
- } catch (IOException e) {
- throw new AssertionError(e);
- } finally {
- if (dexFile != null) {
- try {
- dexFile.close();
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
- }
- Log.d(TAG, "getClasses: -------------------------------");
- }
- } // if DEBUG
-
- List<Class<?>> classes = new ArrayList<>();
- ClassPathScanner scanner = new ClassPathScanner(apks);
-
- ClassPathScanner.ChainedClassNameFilter filter =
- new ClassPathScanner.ChainedClassNameFilter();
- // exclude inner classes
- filter.add(new ClassPathScanner.ExternalClassNameFilter());
-
- // exclude default classes
- for (String defaultExcludedPackage : DEFAULT_EXCLUDED_PACKAGES) {
- filter.add(new ExcludePackageNameFilter(defaultExcludedPackage));
- }
-
- // exclude any classes that aren't a "test class" (see #loadIfTest)
- TestLoader testLoader = new TestLoader();
- testLoader.setClassLoader(loader);
-
- try {
- Set<String> classNames = scanner.getClassPathEntries(filter);
- for (String className : classNames) {
- // Important: This further acts as an additional filter;
- // classes that aren't a "test class" are never loaded.
- Class<?> cls = testLoader.loadIfTest(className);
- if (cls != null) {
- classes.add(cls);
-
- if (DEBUG) {
- Log.d(TAG, "getClasses: Loaded " + className);
- }
- } else if (DEBUG) {
- Log.d(TAG, "getClasses: Failed to load class " + className);
- }
- }
- return classes;
- } catch (IOException e) {
- Log.e(CoreTestRunner.TAG, "Failed to scan classes", e);
- }
-
-
- if (DEBUG) {
- Log.d(TAG, "getClasses: =======================================");
- }
-
- return testLoader.getLoadedClasses();
- }
-
- /**
- * A {@link ClassNameFilter} that only rejects a given package names within the given namespace.
- */
- public static class ExcludePackageNameFilter implements ClassNameFilter {
-
- private final String mPkgName;
-
- ExcludePackageNameFilter(String pkgName) {
- if (!pkgName.endsWith(".")) {
- mPkgName = String.format("%s.", pkgName);
- } else {
- mPkgName = pkgName;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean accept(String pathName) {
- return !pathName.startsWith(mPkgName);
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/TestList.java b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
deleted file mode 100644
index 9d97501..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/TestList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner;
-
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-/**
- * A list of the tests to run.
- */
-class TestList {
-
- /** The set of test pacakges to run */
- private final Set<String> mIncludedPackages = new HashSet<>();
-
- /** The set of test packages not to run */
- private final Set<String> mExcludedPackages = new HashSet<>();
-
- /** The set of tests (classes or methods) to run */
- private final Set<String> mIncludedTests = new HashSet<>();
-
- /** The set of tests (classes or methods) not to run */
- private final Set<String> mExcludedTests = new HashSet<>();
-
- /** The list of all test classes to run (without filtering applied)*/
- private final Collection<Class<?>> classesToRun;
-
- public static TestList rootList(List<String> rootList) {
-
- // Run from the root test class.
- Set<String> classNamesToRun = new LinkedHashSet<>(rootList);
- Log.d(CoreTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
-
- List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
-
- return new TestList(classesToRun1);
- }
-
- private static List<Class<?>> getClasses(Set<String> classNames) {
- // Populate the list of classes to run.
- List<Class<?>> classesToRun = new ArrayList<>();
- for (String className : classNames) {
- try {
- classesToRun.add(Class.forName(className));
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("Could not load class '" + className, e);
- }
- }
- return classesToRun;
- }
-
- /**
- * @param classes The list of classes to run.
- */
- public TestList(Collection<Class<?>> classes) {
- this.classesToRun = classes;
- }
-
- public void addIncludeTestPackages(Set<String> packageNameSet) {
- mIncludedPackages.addAll(packageNameSet);
- }
-
- public void addExcludeTestPackages(Set<String> packageNameSet) {
- mExcludedPackages.addAll(packageNameSet);
- }
-
- public void addIncludeTests(Set<String> testNameSet) {
- mIncludedTests.addAll(testNameSet);
- }
-
- public void addExcludeTests(Set<String> testNameSet) {
- mExcludedTests.addAll(testNameSet);
- }
-
- /**
- * Return all the classes to run.
- */
- public Class[] getClassesToRun() {
- return classesToRun.toArray(new Class[classesToRun.size()]);
- }
-
- /**
- * Return true if the test with the specified name should be run, false otherwise.
- */
- public boolean shouldRunTest(String testName) {
-
- int index = testName.indexOf('#');
- String className;
- if (index == -1) {
- className = testName;
- } else {
- className = testName.substring(0, index);
- }
- try {
- Class<?> testClass = Class.forName(className);
- Package testPackage = testClass.getPackage();
- String testPackageName = "";
- if (testPackage != null) {
- testPackageName = testPackage.getName();
- }
-
- boolean include =
- (mIncludedPackages.isEmpty() || mIncludedPackages.contains(testPackageName)) &&
- (mIncludedTests.isEmpty() || mIncludedTests.contains(className) ||
- mIncludedTests.contains(testName));
-
- boolean exclude =
- mExcludedPackages.contains(testPackageName) ||
- mExcludedTests.contains(className) ||
- mExcludedTests.contains(testName);
-
- return include && !exclude;
- } catch (ClassNotFoundException e) {
- Log.w("Could not load class '" + className, e);
- return false;
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
deleted file mode 100644
index 91df2b9..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.core.runner.support;
-
-import android.support.test.internal.runner.junit3.AndroidJUnit3Builder;
-import android.support.test.internal.runner.junit3.AndroidSuiteBuilder;
-import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
-import android.support.test.internal.runner.junit4.AndroidJUnit4Builder;
-import android.support.test.internal.util.AndroidRunnerParams;
-
-import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
-import org.junit.internal.builders.AnnotatedBuilder;
-import org.junit.internal.builders.IgnoredBuilder;
-import org.junit.internal.builders.JUnit3Builder;
-import org.junit.internal.builders.JUnit4Builder;
-import org.junit.runners.model.RunnerBuilder;
-
-/**
- * A {@link RunnerBuilder} that can handle all types of tests.
- */
-// A copy of package private class android.support.test.internal.runner.AndroidRunnerBuilder.
-// Copied here so that it can be extended.
-class AndroidRunnerBuilder extends AllDefaultPossibilitiesBuilder {
-
- private final AndroidJUnit3Builder mAndroidJUnit3Builder;
- private final AndroidJUnit4Builder mAndroidJUnit4Builder;
- private final AndroidSuiteBuilder mAndroidSuiteBuilder;
- private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
- // TODO: customize for Android ?
- private final IgnoredBuilder mIgnoredBuilder;
-
- /**
- * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
- */
- // Added canUseSuiteMethod parameter.
- AndroidRunnerBuilder(AndroidRunnerParams runnerParams, boolean canUseSuiteMethod) {
- super(canUseSuiteMethod);
- mAndroidJUnit3Builder = new AndroidJUnit3Builder(runnerParams);
- mAndroidJUnit4Builder = new AndroidJUnit4Builder(runnerParams);
- mAndroidSuiteBuilder = new AndroidSuiteBuilder(runnerParams);
- mAndroidAnnotatedBuilder = new AndroidAnnotatedBuilder(this, runnerParams);
- mIgnoredBuilder = new IgnoredBuilder();
- }
-
- @Override
- protected JUnit4Builder junit4Builder() {
- return mAndroidJUnit4Builder;
- }
-
- @Override
- protected JUnit3Builder junit3Builder() {
- return mAndroidJUnit3Builder;
- }
-
- @Override
- protected AnnotatedBuilder annotatedBuilder() {
- return mAndroidAnnotatedBuilder;
- }
-
- @Override
- protected IgnoredBuilder ignoredBuilder() {
- return mIgnoredBuilder;
- }
-
- @Override
- protected RunnerBuilder suiteMethodBuilder() {
- return mAndroidSuiteBuilder;
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
deleted file mode 100644
index a2f95e2..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.core.runner.support;
-
-import android.support.test.internal.util.AndroidRunnerParams;
-import android.util.Log;
-import org.junit.runners.model.RunnerBuilder;
-import org.junit.runner.Runner;
-
-/**
- * Extends {@link AndroidRunnerBuilder} in order to provide alternate {@link RunnerBuilder}
- * implementations.
- */
-public class ExtendedAndroidRunnerBuilder extends AndroidRunnerBuilder {
-
- private static final boolean DEBUG = false;
-
- private final TestNgRunnerBuilder mTestNgBuilder;
-
- /**
- * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
- */
- public ExtendedAndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
- super(runnerParams, false /* CTSv1 filtered out Test suite() classes. */);
- mTestNgBuilder = new TestNgRunnerBuilder();
- }
-
- @Override
- public Runner runnerForClass(Class<?> testClass) throws Throwable {
- if (DEBUG) {
- Log.d("ExAndRunBuild", "runnerForClass: Searching runner for class " + testClass.getName());
- }
-
- // Give TestNG tests a chance to participate in the Runner search first.
- // (Note that the TestNG runner handles log-only runs by itself)
- Runner runner = mTestNgBuilder.runnerForClass(testClass);
- if (runner == null) {
- // Use the normal Runner search mechanism (for Junit tests).
- runner = super.runnerForClass(testClass);
- }
-
- logFoundRunner(runner);
- return runner;
- }
-
- private static void logFoundRunner(Runner runner) {
- if (DEBUG) {
- Log.d("ExAndRunBuild", "runnerForClass: Found runner of type " +
- ((runner == null) ? "<null>" : runner.getClass().getName()));
- }
- }
-}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
index 1465bf0..2f084b3 100644
--- a/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/TestNgRunnerBuilder.java
@@ -24,9 +24,9 @@
import org.testng.annotations.Test;
/**
- * A {@link RunnerBuilder} that can TestNG tests.
+ * A {@link RunnerBuilder} that can handle TestNG tests.
*/
-class TestNgRunnerBuilder extends RunnerBuilder {
+public class TestNgRunnerBuilder extends RunnerBuilder {
// Returns a TestNG runner for this class, only if it is a class
// annotated with testng's @Test or has any methods with @Test in it.
@Override
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
deleted file mode 100644
index 3ccec3c..0000000
--- a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Contains all the changes needed to the {@code android.support.test.internal.runner} classes.
- *
- * <p>As its name suggests {@code android.support.test.internal.runner} are internal classes that
- * are not designed to be extended from outside those packages. This package encapsulates all the
- * workarounds needed to overcome that limitation, from duplicating classes to using reflection.
- * The intention is that these changes are temporary and they (or a better equivalent) will be
- * quickly integrated into the internal classes.
- */
-package com.android.cts.core.runner.support;
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
deleted file mode 100644
index 08c2a5e..0000000
--- a/tests/expectations/knownfailures.txt
+++ /dev/null
@@ -1,282 +0,0 @@
-[
-{
- description: "Disable ListeningPortsTest",
- names: [
- "android.security.cts.ListeningPortsTest"
- ],
- bug: 31803630
-},
-{
- description: "some AlarmClockTests are not robust across different device types",
- names: [
- "android.alarmclock.cts.DismissAlarmTest#testAll",
- "android.alarmclock.cts.SetAlarmTest#testAll",
- "android.alarmclock.cts.SnoozeAlarmTest#testAll"
- ],
- bug: 23776083
-},
-{
- description: "the UsageStats is not yet stable enough",
- names: [
- "android.app.usage.cts.UsageStatsTest"
- ],
- bug: 17536113
-},
-{
- description: "the ConnectivityConstraintTest are not yet stable",
- names: [
- "android.jobscheduler.cts.ConnectivityConstraintTest"
- ],
- bug: 18117279
-},
-{
- description: "tests a fragile by nature as they rely on hardcoded behavior",
- names: [
- "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText",
- "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend"
- ],
- bug: 17595050
-},
-{
- description: "test fails on some devices",
- names: [
- "android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput",
- "android.dumpsys.cts.DumpsysHostTest#testGfxinfoFramestats"
- ],
- bug: 23776893
-},
-{
- description: "the SSLCertificateSocketFactoryTest often fails because of lack of live internet or short timeout, it should be refactored to do a local server testing",
- names: [
- "android.net.cts.SSLCertificateSocketFactoryTest#testCreateSocket",
- "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind",
- "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple",
- "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping"
- ],
- bug: 18682315
-},
-{
- description: "the test result are too much dependent on live-internet connection, which for some devices might not exist",
- names: [
- "android.net.wifi.cts.NsdManagerTest#testAndroidTestCaseSetupProperly"
- ],
- bug: 18680089
-},
-{
- description: "AudioPolicyBinder tests are not yet robust enough",
- names: [
- "android.security.cts.AudioPolicyBinderTest"
- ],
- bug: 18461670
-},
-{
- description: "test not robust",
- names: [
- "android.telecom.cts.ExtendedInCallServiceTest#testAddNewOutgoingCallAndThenDisconnect",
- "android.telecom.cts.RemoteConferenceTest#testRemoteConferenceCallbacks_ConferenceableConnections"
- ],
- bug: 23604254
-},
-{
- description: "tests too flaky",
- names: [
- "android.transition.cts.ChangeScrollTest#testChangeScroll"
- ],
- bug: 23779020
-},
-{
- description: "Not all jdwp features are currently supported. These tests will fail",
- names: [
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001",
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch002",
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch003",
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch004",
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger001#testDebugger002",
- "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowLaunchDebugger002#testDebugger",
- "org.apache.harmony.jpda.tests.jdwp.Events.ClassUnloadTest#testClassUnloadEvent",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnterTest#testMonitorContendedEnterForClassMatch",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorContendedEnteredTest#testMonitorContendedEnteredForClassMatch",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassExclude",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchExact",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchFirst",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassMatchSecond",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitTest#testMonitorWaitForClassOnly",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassExclude",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchExact",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchFirst",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassMatchSecond",
- "org.apache.harmony.jpda.tests.jdwp.Events.MonitorWaitedTest#testMonitorWaitedForClassOnly",
- "org.apache.harmony.jpda.tests.jdwp.ReferenceType.ClassFileVersionTest#testClassFileVersion001",
- "org.apache.harmony.jpda.tests.jdwp.ReferenceType.NestedTypesTest#testNestedTypes001",
- "org.apache.harmony.jpda.tests.jdwp.ThreadReference.StopTest#testStop001",
- "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.HoldEventsTest#testHoldEvents001",
- "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.ReleaseEventsTest#testReleaseEvents001"
- ],
- bug: 16720689
-},
-{
- description: "test can only run properly on a user build device when the bug is resolved",
- names: [
- "android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks",
- "android.appwidget.cts.AppWidgetTest#testBindAppWidget",
- "android.appwidget.cts.AppWidgetTest#testCollectionWidgets",
- "android.appwidget.cts.AppWidgetTest#testDeleteHost",
- "android.appwidget.cts.AppWidgetTest#testDeleteHosts",
- "android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds",
- "android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo",
- "android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions",
- "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId",
- "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds",
- "android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks",
- "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName",
- "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId",
- "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds"
- ],
- bug: 17993121
-},
-{
- description: "permissions for the API previously used in the test has changed, making it impossible to pass",
- names: [
- "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingFast",
- "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow"
- ],
- bug: 17394321
-},
-{
- description: "unexpected failures",
- names: [
- "android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers"
- ],
- bug: 18091590
-},
-{
- description: "Test is not yet properly implemented",
- names: [
- "android.voicesettings.cts.ZenModeTest#testAll"
- ],
- bug: 23238984
-},
-{
- description: "This test failed on devices that use effect off loading. In addition it uses hidden apis",
- names: [
- "android.media.cts.AudioEffectTest#test1_1ConstructorFromUuid"
- ],
- bug: 17605875
-},
-{
- description: "This test failed on hw decoder that doesn't output frame with the configured format.",
- names: [
- "android.media.cts.ImageReaderDecoderTest#testHwAVCDecode360pForFlexibleYuv"
- ],
- bug: 17144778
-},
-{
- description: "android.keystore tests will replace these tests",
- names: [
- "com.android.org.conscrypt.MacTest#test_getInstance_OpenSSL_ENGINE",
- "com.android.org.conscrypt.NativeCryptoTest#test_ENGINE_by_id_TestEngine",
- "com.android.org.conscrypt.SignatureTest#test_getInstance_OpenSSL_ENGINE"
- ],
- bug: 18030049
-},
-{
- description: "The new prepare performance test is not yet passing on all devices",
- names: [
- "android.hardware.camera2.cts.SurfaceViewPreviewTest#testPreparePerformance"
- ],
- bug: 17989532
-},
-{
- description: "The timing measurements for preview callbacks are not reliable",
- names: [
- "android.hardware.cts.CameraTest#testPreviewFpsRange"
- ],
- bug: 23008511
-},
-{
- description: "Light status bar CTS coming in late",
- names: [
- "android.systemui.cts.LightStatusBarTests#testLightStatusBarIcons"
- ],
- bug: 23427621
-},
-{
- description: "tests are not yet ready",
- names: [
- "com.android.cts.app.os.OsHostTests#testNonExportedActivities"
- ],
- bug: 23779168
-},
-{
- description: "ConnectivityConstraintTest job scheduler not working.",
- names: [
- "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi",
- "android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintExecutes_withWifi",
- "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withMobile"
- ],
- bug: 21262226
-},
-{
- description: "ConnectivityConstraintTest times out.",
- names: [
- "android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline"
- ],
- bug: 23144425
-},
-{
- description: "Video encoding tests are timing out.",
- names: [
- "android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW",
- "android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW"
- ],
- bug: 23827982
-},
-{
- description: "protected broadcast not working",
- names: [
- "android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
- ],
- bug: 23192492
-},
-{
- description: "restricted network is not working",
- names: [
- "android.net.cts.ConnectivityManagerTest#testRestrictedNetworks"
- ],
- bug: 25651805
-},
-{
- description: "unit testing for MediaPreparer lives within mediastress module",
- names: [
- "android.mediastress.cts.preconditions.MediaPreparerTest"
- ],
- bug: 25850508
-},
-{
- description: "Tests for the signature tests should not be in CTS",
- names: [
- "android.signature.cts.tests"
- ],
- bug: 26150806
-},
-{
- description: "android.security.cts is using a Non-NDK library, libmedia_jni.so",
- names: [
- "android.security.cts.MediaCryptoTest#testMediaCryptoClearKey",
- "android.security.cts.MediaCryptoTest#testMediaCryptoWidevine"
- ],
- bug: 27218502
-},
-{
- description: "Still investigating this, root cause unknown yet",
- bug: 27578806,
- names: ["com.android.cts.cpptools.RunAsHostTest#testRunAs"]
-},
-{
- description: "Wired headset tests are no longer a requirement per CDD",
- names: [
- "android.telecom.cts.WiredHeadsetTest"
- ],
- bug: 26149528
-}
-]
diff --git a/tests/libcore/jsr166/AndroidManifest.xml b/tests/libcore/jsr166/AndroidManifest.xml
index baae488..5fd3f6e 100644
--- a/tests/libcore/jsr166/AndroidManifest.xml
+++ b/tests/libcore/jsr166/AndroidManifest.xml
@@ -22,6 +22,9 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.cts.jsr166"
- android:label="CTS Libcore JSR166 test cases" />
+ android:label="CTS Libcore JSR166 test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/jsr166/AndroidTest.xml b/tests/libcore/jsr166/AndroidTest.xml
index 2a3e5d2..0c67705 100644
--- a/tests/libcore/jsr166/AndroidTest.xml
+++ b/tests/libcore/jsr166/AndroidTest.xml
@@ -27,8 +27,6 @@
</target_preparer>
<test class="com.android.compatibility.testtype.LibcoreTest" >
<option name="package" value="android.libcore.cts.jsr166" />
- <option name="instrumentation-arg" key="listener"
- value="com.android.cts.runner.CtsTestRunListener" />
<option name="instrumentation-arg" key="filter"
value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/luni/AndroidManifest.xml b/tests/libcore/luni/AndroidManifest.xml
index 0389be6..4df4b93 100644
--- a/tests/libcore/luni/AndroidManifest.xml
+++ b/tests/libcore/luni/AndroidManifest.xml
@@ -23,6 +23,9 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.cts"
- android:label="CTS Libcore test cases" />
+ android:label="CTS Libcore test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/luni/AndroidTest.xml b/tests/libcore/luni/AndroidTest.xml
index a8c4142..fa1c9cc 100644
--- a/tests/libcore/luni/AndroidTest.xml
+++ b/tests/libcore/luni/AndroidTest.xml
@@ -27,8 +27,6 @@
</target_preparer>
<test class="com.android.compatibility.testtype.LibcoreTest" >
<option name="package" value="android.libcore.cts" />
- <option name="instrumentation-arg" key="listener"
- value="com.android.cts.runner.CtsTestRunListener" />
<option name="instrumentation-arg" key="filter"
value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/ojluni/AndroidManifest.xml b/tests/libcore/ojluni/AndroidManifest.xml
index 5f900a9..8c45c30 100644
--- a/tests/libcore/ojluni/AndroidManifest.xml
+++ b/tests/libcore/ojluni/AndroidManifest.xml
@@ -18,9 +18,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.libcore.cts.oj">
<uses-permission android:name="android.permission.INTERNET" />
- <!-- important: instrument another package which actually contains the CTS core test runner -->
- <instrumentation android:name="com.android.cts.core.runner.CoreTestRunner"
+ <!-- important: instrument another package which actually contains AJUR -->
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.runner"
- android:label="CTS Libcore OJ test cases" />
+ android:label="CTS Libcore OJ test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/ojluni/AndroidTest.xml b/tests/libcore/ojluni/AndroidTest.xml
index 9bf7113..2b7ae29 100644
--- a/tests/libcore/ojluni/AndroidTest.xml
+++ b/tests/libcore/ojluni/AndroidTest.xml
@@ -22,17 +22,17 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <!-- this has the CoreTestRunner which needs to be in a separate APK -->
+ <!-- this has the AJUR which needs to be in a separate APK -->
<option name="test-file-name" value="CtsLibcoreTestRunner.apk" />
<!-- this has just the instrumentation which acts as the tests we want to run -->
<option name="test-file-name" value="CtsLibcoreOjTestCases.apk" />
</target_preparer>
<test class="com.android.compatibility.testtype.LibcoreTest" >
- <!-- override AJUR -->
- <option name="runner" value="com.android.cts.core.runner.CoreTestRunner" />
<option name="package" value="android.libcore.cts.oj" />
- <option name="instrumentation-arg" key="core-listener"
- value="com.android.cts.runner.CtsTestRunListener"/>
+ <option name="instrumentation-arg" key="runnerBuilder"
+ value="com.android.cts.core.runner.support.TestNgRunnerBuilder"/>
+ <option name="instrumentation-arg" key="filter"
+ value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
<option name="runtime-hint" value="35m"/>
<!-- 20x default timeout of 600sec -->
diff --git a/tests/libcore/okhttp/AndroidManifest.xml b/tests/libcore/okhttp/AndroidManifest.xml
index 151fda9..a96448d 100644
--- a/tests/libcore/okhttp/AndroidManifest.xml
+++ b/tests/libcore/okhttp/AndroidManifest.xml
@@ -23,6 +23,9 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.cts.okhttp"
- android:label="CTS Libcore OkHttp test cases" />
+ android:label="CTS Libcore OkHttp test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/okhttp/AndroidTest.xml b/tests/libcore/okhttp/AndroidTest.xml
index 4e79b80..c3470cc 100644
--- a/tests/libcore/okhttp/AndroidTest.xml
+++ b/tests/libcore/okhttp/AndroidTest.xml
@@ -27,8 +27,6 @@
</target_preparer>
<test class="com.android.compatibility.testtype.LibcoreTest" >
<option name="package" value="android.libcore.cts.okhttp" />
- <option name="instrumentation-arg" key="listener"
- value="com.android.cts.runner.CtsTestRunListener" />
<option name="instrumentation-arg" key="filter"
value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/wycheproof-bc/AndroidManifest.xml b/tests/libcore/wycheproof-bc/AndroidManifest.xml
index 15c5fd5..fb53977 100644
--- a/tests/libcore/wycheproof-bc/AndroidManifest.xml
+++ b/tests/libcore/wycheproof-bc/AndroidManifest.xml
@@ -23,6 +23,9 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.cts.wycheproof.bouncycastle"
- android:label="CTS Libcore Wycheproof Bouncy Castle test cases" />
+ android:label="CTS Libcore Wycheproof Bouncy Castle test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/wycheproof-bc/AndroidTest.xml b/tests/libcore/wycheproof-bc/AndroidTest.xml
index 9c3a50a..ac761f3 100644
--- a/tests/libcore/wycheproof-bc/AndroidTest.xml
+++ b/tests/libcore/wycheproof-bc/AndroidTest.xml
@@ -26,8 +26,6 @@
context of one of the suites, so we have to limit the test
infrastructure to only running the test suites. -->
<option name="test-package" value="android.libcore.cts.wycheproof" />
- <option name="instrumentation-arg" key="listener"
- value="com.android.cts.runner.CtsTestRunListener" />
<option name="instrumentation-arg" key="filter"
value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/libcore/wycheproof/AndroidManifest.xml b/tests/libcore/wycheproof/AndroidManifest.xml
index 765c677..5e8058f 100644
--- a/tests/libcore/wycheproof/AndroidManifest.xml
+++ b/tests/libcore/wycheproof/AndroidManifest.xml
@@ -23,6 +23,9 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.libcore.cts.wycheproof.conscrypt"
- android:label="CTS Libcore Wycheproof Conscrypt test cases" />
+ android:label="CTS Libcore Wycheproof Conscrypt test cases">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
</manifest>
diff --git a/tests/libcore/wycheproof/AndroidTest.xml b/tests/libcore/wycheproof/AndroidTest.xml
index b5874fd..0c713b9 100644
--- a/tests/libcore/wycheproof/AndroidTest.xml
+++ b/tests/libcore/wycheproof/AndroidTest.xml
@@ -26,8 +26,6 @@
context of one of the suites, so we have to limit the test
infrastructure to only running the test suites. -->
<option name="test-package" value="android.libcore.cts.wycheproof" />
- <option name="instrumentation-arg" key="listener"
- value="com.android.cts.runner.CtsTestRunListener" />
<option name="instrumentation-arg" key="filter"
value="com.android.cts.core.runner.ExpectationBasedFilter" />
<option name="core-expectation" value="/knownfailures.txt" />
diff --git a/tests/pdf/res/raw/protected_pdf.pdf b/tests/pdf/res/raw/protected_pdf.pdf
new file mode 100644
index 0000000..e4092b9
--- /dev/null
+++ b/tests/pdf/res/raw/protected_pdf.pdf
Binary files differ
diff --git a/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
index 2f0158e..2ce69d1 100644
--- a/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -62,6 +62,7 @@
private static final int A5_PORTRAIT_PRINTSCALING_NONE =
R.raw.a5_portrait_rgbb_1_6_printscaling_none;
private static final int TWO_PAGES = R.raw.two_pages;
+ private static final int PROTECTED_PDF = R.raw.protected_pdf;
private Context mContext;
@@ -76,12 +77,28 @@
}
@Test
- @Ignore("Makes all subsequent tests fail")
public void constructRendererFromNonPDF() throws Exception {
// Open jpg as if it was a PDF
- ParcelFileDescriptor fd = mContext.getResources().openRawResourceFd(R.raw.testimage)
- .getParcelFileDescriptor();
- verifyException(() -> new PdfRenderer(fd), IOException.class);
+ verifyException(() -> createRenderer(R.raw.testimage, mContext), IOException.class);
+ }
+
+ @Test
+ public void constructRendererFromProtectedPDF() throws Exception {
+ verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);
+ }
+
+ @Test
+ public void rendererRecoversAfterFailure() throws Exception {
+ // Create rendered to prevent lib from being unloaded
+ PdfRenderer firstRenderer = createRenderer(A4_PORTRAIT, mContext);
+
+ verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);
+
+ // We can create new renderers after we failed to create one
+ PdfRenderer renderer = createRenderer(TWO_PAGES, mContext);
+ renderer.close();
+
+ firstRenderer.close();
}
@Test
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
index df69004..b382698 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
+++ b/tests/signature/api-check/apache-http-legacy-current-api/Android.mk
@@ -19,6 +19,6 @@
LOCAL_PACKAGE_NAME := CtsApacheHttpLegacyCurrentApiSignatureTestCases
LOCAL_SIGNATURE_API_FILES := \
- apache-http-legacy-current.api \
+ apache-http-legacy-minus-current.api \
include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
index a5e69a9..a9db2b0 100644
--- a/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/apache-http-legacy-current-api/AndroidTest.xml
@@ -20,7 +20,7 @@
<option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="push" value="apache-http-legacy-current.api->/data/local/tmp/signature-test/apache-http-legacy-current.api" />
+ <option name="push" value="apache-http-legacy-minus-current.api->/data/local/tmp/signature-test/apache-http-legacy-minus-current.api" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
@@ -29,7 +29,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.signature.cts.api.apache_http_legacy_current" />
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
- <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-current.api" />
+ <option name="instrumentation-arg" key="expected-api-files" value="apache-http-legacy-minus-current.api" />
<option name="runtime-hint" value="5s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
index 08cc051..062c41f 100644
--- a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
@@ -55,6 +55,9 @@
KNOWN_INACCESSIBLE_CLASSES.add("android.os.UserManager.UserRestrictionSource");
KNOWN_INACCESSIBLE_CLASSES.add(
"android.service.persistentdata.PersistentDataBlockManager.FlashLockState");
+ KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.ProgramSelector.IdentifierType");
+ KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.ProgramSelector.ProgramType");
+ KNOWN_INACCESSIBLE_CLASSES.add("android.hardware.radio.RadioManager.Band");
}
private TestResultObserver mResultObserver;
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index 29328cb..05aa3c0 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -66,11 +66,28 @@
include $(LOCAL_PATH)/build_xml_api_file.mk
-# current apache-http-legacy api, in XML format.
-# ==============================================
+# current apache-http-legacy minus current api, in text format.
+# =============================================================
+# Removes any classes from the org.apache.http.legacy API description that are
+# also part of the Android API description.
include $(CLEAR_VARS)
-LOCAL_MODULE := cts-apache-http-legacy-current-api
-LOCAL_MODULE_STEM := apache-http-legacy-current.api
-LOCAL_SRC_FILES := external/apache-http/api/apache-http-legacy-current.txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_ETC)
-include $(LOCAL_PATH)/build_xml_api_file.mk
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_MODULE := cts-apache-http-legacy-minus-current-api
+LOCAL_MODULE_STEM := apache-http-legacy-minus-current.api
+
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE) : \
+ frameworks/base/api/current.txt \
+ external/apache-http/api/apache-http-legacy-current.txt \
+ | $(APICHECK)
+ @echo "Generate unique Apache Http Legacy API file -> $@"
+ @mkdir -p $(dir $@)
+ $(hide) $(APICHECK_COMMAND) -new_api_no_strip \
+ frameworks/base/api/current.txt \
+ external/apache-http/api/apache-http-legacy-current.txt \
+ $@
diff --git a/tests/tests/debug/Android.mk b/tests/tests/debug/Android.mk
index f1b9b27..c715d07 100644
--- a/tests/tests/debug/Android.mk
+++ b/tests/tests/debug/Android.mk
@@ -30,7 +30,7 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner nativetesthelper
LOCAL_JNI_SHARED_LIBRARIES := libdebugtest
diff --git a/tests/tests/debug/AndroidManifest.xml b/tests/tests/debug/AndroidManifest.xml
index 4b3254a..091e778 100644
--- a/tests/tests/debug/AndroidManifest.xml
+++ b/tests/tests/debug/AndroidManifest.xml
@@ -26,8 +26,6 @@
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.debug.cts"
android:label="CTS tests of native debugging API">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
</manifest>
diff --git a/tests/tests/debug/libdebugtest/Android.mk b/tests/tests/debug/libdebugtest/Android.mk
index 65c9756..aca41a3 100644
--- a/tests/tests/debug/libdebugtest/Android.mk
+++ b/tests/tests/debug/libdebugtest/Android.mk
@@ -29,6 +29,7 @@
android_debug_cts.cpp
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := libnativetesthelper_jni
LOCAL_SDK_VERSION := 23
LOCAL_NDK_STL_VARIANT := c++_static
diff --git a/tests/tests/debug/libdebugtest/android_debug_cts.cpp b/tests/tests/debug/libdebugtest/android_debug_cts.cpp
index 2c7c967..6ea8324 100644
--- a/tests/tests/debug/libdebugtest/android_debug_cts.cpp
+++ b/tests/tests/debug/libdebugtest/android_debug_cts.cpp
@@ -15,6 +15,7 @@
*/
#include <jni.h>
+#include <gtest/gtest.h>
#include <android/log.h>
#include <sys/ptrace.h>
@@ -28,6 +29,7 @@
#define LOG_TAG "Cts-DebugTest"
+// Used by child processes only
#define assert_or_exit(x) \
do { \
if(x) break; \
@@ -35,29 +37,21 @@
errno, strerror(errno)); \
_exit(1); \
} while (0)
-#define assert_or_return(x) \
- do { \
- if(x) break; \
- __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Assertion " #x " failed. errno(%d): %s", \
- errno, strerror(errno)); \
- return false; \
- } while (0)
-static bool parent(pid_t child) {
+static void parent(pid_t child) {
int status;
int wpid = waitpid(child, &status, 0);
- assert_or_return(wpid == child);
- assert_or_return(WIFEXITED(status));
- assert_or_return(WEXITSTATUS(status ) == 0);
- return true;
+ ASSERT_EQ(child, wpid);
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
}
-static bool run_test(const std::function<void(pid_t)> &test) {
+static void run_test(const std::function<void(pid_t)> &test) {
pid_t pid = fork();
- assert_or_return(pid >= 0);
- if (pid != 0)
- return parent(pid);
- else {
+ ASSERT_NE(-1, pid) << "fork() failed with " << strerror(errno);
+ if (pid != 0) {
+ parent(pid);
+ } else {
// child
test(getppid());
_exit(0);
@@ -74,12 +68,10 @@
assert_or_exit(ptrace(PTRACE_DETACH, parent, nullptr, nullptr) == 0);
}
-// public static native boolean ptraceAttach();
-extern "C" jboolean Java_android_debug_cts_DebugTest_ptraceAttach(JNIEnv *, jclass) {
- return run_test(ptraceAttach);
+TEST(DebugTest, ptraceAttach) {
+ run_test(ptraceAttach);
}
-
static void processVmReadv(pid_t parent, const std::vector<long *> &addresses) {
long destination;
iovec local = { &destination, sizeof destination };
@@ -98,11 +90,11 @@
static long global_variable = 0x47474747;
// public static native boolean processVmReadv();
-extern "C" jboolean Java_android_debug_cts_DebugTest_processVmReadv(JNIEnv *, jclass) {
+TEST(DebugTest, processVmReadv) {
long stack_variable = 0x42424242;
// This runs the test with a selection of different kinds of addresses and
// makes sure the child process (simulating a debugger) can read them.
- return run_test([&](pid_t parent) {
+ run_test([&](pid_t parent) {
processVmReadv(parent, std::vector<long *>{
&global_variable, &stack_variable,
reinterpret_cast<long *>(&processVmReadv)});
@@ -110,9 +102,9 @@
}
// public static native boolean processVmReadvNullptr();
-extern "C" jboolean Java_android_debug_cts_DebugTest_processVmReadvNullptr(JNIEnv *, jclass) {
+TEST(DebugTest, processVmReadvNullptr) {
// Make sure reading unallocated memory behaves reasonably.
- return run_test([](pid_t parent) {
+ run_test([](pid_t parent) {
long destination;
iovec local = {&destination, sizeof destination};
iovec remote = {nullptr, sizeof(long)};
diff --git a/tests/tests/debug/src/android/debug/cts/DebugTest.java b/tests/tests/debug/src/android/debug/cts/DebugTest.java
index ca55d9c..993f02b 100644
--- a/tests/tests/debug/src/android/debug/cts/DebugTest.java
+++ b/tests/tests/debug/src/android/debug/cts/DebugTest.java
@@ -16,26 +16,10 @@
package android.debug.cts;
-import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
-public class DebugTest extends TestCase {
-
- static {
- System.loadLibrary("debugtest");
- }
-
- public static native boolean ptraceAttach();
- public void test_ptraceAttach() {
- assertEquals(true, ptraceAttach());
- }
-
- public static native boolean processVmReadv();
- public void test_processVmReadv() {
- assertEquals(true, processVmReadv());
- }
-
- public static native boolean processVmReadvNullptr();
- public void test_processVmReadvNullptr() {
- assertEquals(true, processVmReadvNullptr());
- }
-}
+@RunWith(GtestRunner.class)
+@TargetLibrary("debugtest")
+public class DebugTest {}
diff --git a/tests/tests/graphics/assets/a3em.ttx b/tests/tests/graphics/assets/a3em.ttx
new file mode 100644
index 0000000..d3b9e16
--- /dev/null
+++ b/tests/tests/graphics/assets/a3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="1em"/>
+ <GlyphID id="2" name="3em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="1em" width="1000" lsb="93"/>
+ <mtx name="3em" width="3000" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="3em" />
+ <map code="0x0062" name="1em" />
+ <map code="0x0063" name="1em" />
+ <map code="0x0064" name="1em" />
+ <map code="0x0065" name="1em" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/assets/b3em.ttx b/tests/tests/graphics/assets/b3em.ttx
new file mode 100644
index 0000000..b5a77ef
--- /dev/null
+++ b/tests/tests/graphics/assets/b3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="1em"/>
+ <GlyphID id="2" name="3em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="1em" width="1000" lsb="93"/>
+ <mtx name="3em" width="3000" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="1em" />
+ <map code="0x0062" name="3em" />
+ <map code="0x0063" name="1em" />
+ <map code="0x0064" name="1em" />
+ <map code="0x0065" name="1em" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/assets/c3em.ttx b/tests/tests/graphics/assets/c3em.ttx
new file mode 100644
index 0000000..f5ed8e5
--- /dev/null
+++ b/tests/tests/graphics/assets/c3em.ttx
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="1em"/>
+ <GlyphID id="2" name="3em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="1em" width="1000" lsb="93"/>
+ <mtx name="3em" width="3000" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="1em" />
+ <map code="0x0062" name="1em" />
+ <map code="0x0063" name="3em" />
+ <map code="0x0064" name="1em" />
+ <map code="0x0065" name="1em" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
index 38339b7..32a7516 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_drawable_scale_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
index be487d1..6cafa84 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
index 943fce5..b0b6eb5 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_create_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
index b46363e..9f60a31 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_delete_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
index 01c445c..452e3ab 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
index 739eea1..767a3e1 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
index 4617f62..48bccdb 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
index 4d6b84d..680bb70 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
index c6540e8..ccdd69d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
index 491e73e..4e5ff8c 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_2_repeat_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index e335a92..65a7131 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
index 57f2ae3..3a0d00b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
index e74c181..c9702c9 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_group_clip_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
index 7450751..b0af7d4 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_heart_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
index d010d79..e779718 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
index 5ada060..2fbf79d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_random_path_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
index 5af7090..060c4b9 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
index 24b9662..b8fe74d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
index c9677a6..9e92c8a 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
index 8882a7a..0262e57 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_repeated_st_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
index 143ce3e..1520397 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
index 9a5efd2..727bb48 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
index 2edc3c7..d68ab90 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_scale_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
index 9822bc2..2830840 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_schedule_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
index d12b142..b5d25be 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_settings_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
index 3936c89..923347d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
index c5d06f6..74c30fa 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_2_pressed_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
index 3936c89..923347d 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
index c5d06f6..74c30fa 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_state_list_pressed_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
index 2bf7882..c202ffc 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
index 4141d6f..ed31e47 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
index 1212fb3..a32de90 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_stroke_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
index 0717399..66e4e3b 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
index 505aa2e..9aeeeef 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_2_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
index 9b53e94..468a1c3 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
index a5d4d33..e4bc055 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_4_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
index 0d8ded1..bb185f2 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_5_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
index 3da7969..02901b6 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_transformation_6_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/font/a3em.ttf b/tests/tests/graphics/res/font/a3em.ttf
new file mode 100644
index 0000000..a601ce2
--- /dev/null
+++ b/tests/tests/graphics/res/font/a3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/b3em.ttf b/tests/tests/graphics/res/font/b3em.ttf
new file mode 100644
index 0000000..63948a2
--- /dev/null
+++ b/tests/tests/graphics/res/font/b3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/c3em.ttf b/tests/tests/graphics/res/font/c3em.ttf
new file mode 100644
index 0000000..badc3e2
--- /dev/null
+++ b/tests/tests/graphics/res/font/c3em.ttf
Binary files differ
diff --git a/tests/tests/graphics/res/font/multistyle_family.xml b/tests/tests/graphics/res/font/multistyle_family.xml
new file mode 100644
index 0000000..2522e72
--- /dev/null
+++ b/tests/tests/graphics/res/font/multistyle_family.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:font="@font/a3em" android:fontWeight="400" android:fontStyle="normal" />
+ <font android:font="@font/b3em" android:fontWeight="400" android:fontStyle="italic" />
+ <font android:font="@font/c3em" android:fontWeight="700" android:fontStyle="italic" />
+</font-family>
diff --git a/tests/tests/graphics/res/font/multiweight_family.xml b/tests/tests/graphics/res/font/multiweight_family.xml
new file mode 100644
index 0000000..2ed0490
--- /dev/null
+++ b/tests/tests/graphics/res/font/multiweight_family.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:font="@font/a3em" android:fontWeight="100" android:fontStyle="normal" />
+ <font android:font="@font/b3em" android:fontWeight="400" android:fontStyle="normal" />
+ <font android:font="@font/c3em" android:fontWeight="700" android:fontStyle="normal" />
+</font-family>
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index ba90c0f..97064b0 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -52,6 +52,19 @@
private static final String DEFAULT = (String)null;
private static final String INVALID = "invalid-family-name";
+ private static final float GLYPH_1EM_WIDTH;
+ private static final float GLYPH_3EM_WIDTH;
+
+ static {
+ // 3em.ttf supports "a", "b", "c". The width of "a" is 3em, others are 1em.
+ final Context ctx = InstrumentationRegistry.getTargetContext();
+ final Typeface typeface = ctx.getResources().getFont(R.font.a3em);
+ final Paint paint = new Paint();
+ paint.setTypeface(typeface);
+ GLYPH_3EM_WIDTH = paint.measureText("a");
+ GLYPH_1EM_WIDTH = paint.measureText("b");
+ }
+
// list of family names to try when attempting to find a typeface with a given style
private static final String[] FAMILIES =
{ (String) null, "monospace", "serif", "sans-serif", "cursive", "arial", "times" };
@@ -515,4 +528,68 @@
assertTrue(Math.abs(widthFromRegular - widthFromBlack) > 1.0f);
}
+
+ @Test
+ public void testTypefaceCreate_withExactWeight() {
+ // multiweight_family has following fonts.
+ // - a3em.ttf with weight = 100, style=normal configuration.
+ // This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
+ // - b3em.ttf with weight = 400, style=normal configuration.
+ // This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
+ // - c3em.ttf with weight = 700, style=normal configuration.
+ // This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
+ final Typeface family = mContext.getResources().getFont(R.font.multiweight_family);
+ assertNotNull(family);
+
+ final Paint paint = new Paint();
+ // By default, the font which weight is 400 is selected.
+ paint.setTypeface(family);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+ // Draw with the font which weight is 100.
+ paint.setTypeface(Typeface.create(family, 100 /* weight */, false /* italic */));
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+ // Draw with the font which weight is 700.
+ paint.setTypeface(Typeface.create(family, 700 /* weight */, false /* italic */));
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0f);
+ }
+
+ @Test
+ public void testTypefaceCreate_withExactStyle() {
+ // multiweight_family has following fonts.
+ // - a3em.ttf with weight = 400, style=normal configuration.
+ // This font supports "a", "b", "c". The weight "a" is 3em, others are 1em.
+ // - b3em.ttf with weight = 400, style=italic configuration.
+ // This font supports "a", "b", "c". The weight "b" is 3em, others are 1em.
+ // - c3em.ttf with weight = 700, style=italic configuration.
+ // This font supports "a", "b", "c". The weight "c" is 3em, others are 1em.
+ final Typeface family = mContext.getResources().getFont(R.font.multistyle_family);
+ assertNotNull(family);
+
+ final Paint paint = new Paint();
+ // By default, the normal style font which weight is 400 is selected.
+ paint.setTypeface(family);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+ // Draw with the italic font.
+ paint.setTypeface(Typeface.create(family, 400 /* weight */, true /* italic */));
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0f);
+
+ // Draw with the italic font which weigth is 700.
+ paint.setTypeface(Typeface.create(family, 700 /* weight */, true /* italic */));
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0f);
+ assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0f);
+ assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0f);
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
index 75d7b7c..8968442 100644
--- a/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/GeomagneticFieldTest.java
@@ -23,26 +23,79 @@
import java.util.GregorianCalendar;
public class GeomagneticFieldTest extends AndroidTestCase {
- // Chengdu: Latitude 30d 40' 12", Longitude 104d 3' 36"
- private static final float LATITUDE_OF_CHENGDU = 30.67f;
- private static final float LONGITUDE_OF_CHENGDU = 104.06f;
- private static final float ALTITUDE_OF_CHENGDU = 500f;
- private static final long TEST_TIME = new GregorianCalendar(2010, 5, 1).getTimeInMillis();
+ private static final float DECLINATION_THRESHOLD = 0.1f;
+ private static final float INCLINATION_THRESHOLD = 0.1f;
+ private static final float FIELD_STRENGTH_THRESHOLD = 100;
@Presubmit
public void testGeomagneticField() {
- GeomagneticField geomagneticField = new GeomagneticField(LATITUDE_OF_CHENGDU,
- LONGITUDE_OF_CHENGDU, ALTITUDE_OF_CHENGDU, TEST_TIME);
+ // Reference values calculated from NOAA online calculator for WMM 2015
+ // https://www.ngdc.noaa.gov/geomag-web/#igrfwmm
+ TestDataPoint testPoints[] = new TestDataPoint[] {
+ // Mountain View, CA, USA on 2017/1/1
+ new TestDataPoint(37.386f, -122.083f, 32, 2017, 1, 1,
+ 13.4589f, 60.9542f, 48168.0f),
+ // Chengdu, China on 2017/8/8
+ new TestDataPoint(30.658f, 103.935f, 500f, 2017, 8, 8,
+ -1.9784f, 47.9723f, 50717.3f),
+ // Sao Paulo, Brazil on 2018/12/25
+ new TestDataPoint(-23.682f, -46.875f, 760f, 2018, 12, 25,
+ -21.3130f, -37.9940f, 22832.3f),
+ // Boston, MA, USA on 2019/2/10
+ new TestDataPoint(42.313f, -71.127f, 43f, 2019, 2, 10,
+ -14.5391f, 66.9693f, 51815.1f),
+ // Cape Town, South Africa on 2019/5/1
+ new TestDataPoint(-33.913f, 18.095f, 100f, 2019, 5, 1,
+ -25.2454f, -65.8887f, 25369.2f),
+ // Sydney, Australia on 2020/1/1
+ new TestDataPoint(-33.847f, 150.791f, 19f, 2020, 1, 1,
+ 12.4469f, -64.3443f, 57087.9f)
+ };
- // Reference values calculated from NOAA online calculator for WMM 2010,
- // and cross-checked in Matlab. The expected deltas are proportional to the
- // magnitude of each value.
- assertEquals(-1.867f, geomagneticField.getDeclination(), 0.1f);
- assertEquals(47.133f, geomagneticField.getInclination(), 1.0f);
- assertEquals(50375.6f, geomagneticField.getFieldStrength(), 100.0f);
- assertEquals(34269.3f, geomagneticField.getHorizontalStrength(), 100.0f);
- assertEquals(34251.2f, geomagneticField.getX(), 100.0f);
- assertEquals(-1113.2f, geomagneticField.getY(), 10.0f);
- assertEquals(36923.1f, geomagneticField.getZ(), 100.0f);
+ for (TestDataPoint t : testPoints) {
+ GeomagneticField field =
+ new GeomagneticField(t.latitude, t.longitude, t.altitude, t.epochTimeMillis);
+ assertEquals(t.declinationDegree, field.getDeclination(), DECLINATION_THRESHOLD);
+ assertEquals(t.inclinationDegree, field.getInclination(), INCLINATION_THRESHOLD);
+ assertEquals(t.fieldStrengthNanoTesla, field.getFieldStrength(),
+ FIELD_STRENGTH_THRESHOLD);
+
+ float horizontalFieldStrengthNanoTesla = (float)(
+ Math.cos(Math.toRadians(t.inclinationDegree)) * t.fieldStrengthNanoTesla);
+ assertEquals(horizontalFieldStrengthNanoTesla, field.getHorizontalStrength(),
+ FIELD_STRENGTH_THRESHOLD);
+
+ float verticalFieldStrengthNanoTesla = (float)(
+ Math.sin(Math.toRadians(t.inclinationDegree)) * t.fieldStrengthNanoTesla);
+ assertEquals(verticalFieldStrengthNanoTesla, field.getZ(), FIELD_STRENGTH_THRESHOLD);
+
+ float declinationDegree = (float)(
+ Math.toDegrees(Math.atan2(field.getY(), field.getX())));
+ assertEquals(t.declinationDegree, declinationDegree, DECLINATION_THRESHOLD);
+ assertEquals(horizontalFieldStrengthNanoTesla,
+ Math.sqrt(field.getX() * field.getX() + field.getY() * field.getY()),
+ FIELD_STRENGTH_THRESHOLD);
+ }
+ }
+
+ private class TestDataPoint {
+ public final float latitude;
+ public final float longitude;
+ public final float altitude;
+ public final long epochTimeMillis;
+ public final float declinationDegree;
+ public final float inclinationDegree;
+ public final float fieldStrengthNanoTesla;
+
+ TestDataPoint(float lat, float lng, float alt, int year, int month, int day,
+ float dec, float inc, float strength) {
+ latitude = lat;
+ longitude = lng;
+ altitude = alt;
+ epochTimeMillis = new GregorianCalendar(year, month, day).getTimeInMillis();
+ declinationDegree = dec;
+ inclinationDegree = inc;
+ fieldStrengthNanoTesla = strength;
+ }
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/GlUtils.java b/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
index 81628d4..bd5cecb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
+++ b/tests/tests/hardware/src/android/hardware/cts/GlUtils.java
@@ -17,6 +17,7 @@
package android.hardware.cts;
import android.opengl.GLES20;
+import android.util.Pair;
import java.util.Arrays;
import java.util.regex.Matcher;
@@ -27,6 +28,10 @@
}
static int getMajorVersion() {
+ return getVersion().first;
+ }
+
+ static Pair<Integer, Integer> getVersion() {
// Section 6.1.5 of the OpenGL ES specification indicates the GL version
// string strictly follows this format:
//
@@ -42,9 +47,10 @@
Pattern pattern = Pattern.compile("OpenGL ES ([0-9]+)\\.([0-9]+)");
Matcher matcher = pattern.matcher(version);
if (matcher.find()) {
- return Integer.parseInt(matcher.group(1));
+ return new Pair<>(
+ Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)));
}
- return 2;
+ return new Pair<>(2, 0);
}
static String[] getExtensions() {
diff --git a/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
index 5ea845a..6276959 100644
--- a/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/HardwareBufferTest.java
@@ -24,6 +24,7 @@
import android.opengl.EGLSurface;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -70,8 +71,10 @@
}, 0);
EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
- sHasFloatBuffers = GlUtils.getMajorVersion() >= 3 ||
- GlUtils.hasExtensions("GL_OES_texture_half_float",
+ Pair<Integer, Integer> version = GlUtils.getVersion();
+ sHasFloatBuffers = (version.first >= 3 && version.second >= 2) ||
+ GlUtils.hasExtensions(
+ "GL_OES_texture_half_float",
"GL_OES_texture_half_float_linear");
EGL14.eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 748b756..77ac34b 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -77,9 +77,7 @@
static bool not_accessible(const std::string& library, const std::string& err) {
return err.find("dlopen failed: library \"" + library + "\"") == 0 &&
- (err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos ||
- err.find("is not accessible for the namespace \"sphal\"") != std::string::npos ||
- err.find("is not accessible for the namespace \"(default)\"") != std::string::npos);
+ err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos;
}
static bool not_found(const std::string& library, const std::string& err) {
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 67c4e3a..a0a8536 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -62,6 +62,9 @@
import android.test.AndroidTestCase;
import android.util.ArraySet;
+import com.android.org.bouncycastle.asn1.x500.X500Name;
+import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -70,6 +73,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.ProviderException;
+import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -422,7 +426,7 @@
try {
Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
- verifyCertificateSignatures(certificates);
+ verifyCertificateChain((X509Certificate[])certificates);
X509Certificate attestationCert = (X509Certificate) certificates[0];
Attestation attestation = new Attestation(attestationCert);
@@ -476,7 +480,7 @@
try {
Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
- verifyCertificateSignatures(certificates);
+ verifyCertificateChain((X509Certificate[])certificates);
X509Certificate attestationCert = (X509Certificate) certificates[0];
Attestation attestation = new Attestation(attestationCert);
@@ -767,8 +771,6 @@
assertNotNull(rootOfTrust);
assertNotNull(rootOfTrust.getVerifiedBootKey());
assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
- assertTrue(rootOfTrust.isDeviceLocked());
- assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
}
private void checkRsaKeyDetails(Attestation attestation, int keySize, int purposes,
@@ -878,12 +880,34 @@
keyPairGenerator.generateKeyPair();
}
- private void verifyCertificateSignatures(Certificate[] certChain)
+ private void verifyCertificateChain(X509Certificate[] certChain)
throws GeneralSecurityException {
assertNotNull(certChain);
for (int i = 1; i < certChain.length; ++i) {
try {
- certChain[i - 1].verify(certChain[i].getPublicKey());
+ PublicKey pubKey = certChain[i].getPublicKey();
+ certChain[i - 1].verify(pubKey);
+ if (i == certChain.length - 1) {
+ // Last cert should be self-signed.
+ certChain[i].verify(pubKey);
+ }
+
+ // Check that issuer in the signed cert matches subject in the signing cert.
+ X500Name signingCertSubject =
+ new JcaX509CertificateHolder(certChain[i]).getSubject();
+ X500Name signedCertIssuer =
+ new JcaX509CertificateHolder(certChain[i - 1]).getIssuer();
+ // Use .toASN1Object().equals() rather than .equals() because .equals() is case
+ // insensitive, and we want to verify an exact match.
+ assertTrue(
+ signedCertIssuer.toASN1Object().equals(signingCertSubject.toASN1Object()));
+
+ if (i == 1) {
+ // First cert should have subject "CN=Android Keystore Key".
+ X500Name signedCertSubject =
+ new JcaX509CertificateHolder(certChain[i - 1]).getSubject();
+ assertEquals(signedCertSubject, new X500Name("CN=Android Keystore Key"));
+ }
} catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException
| NoSuchProviderException | SignatureException e) {
throw new GeneralSecurityException("Failed to verify certificate "
diff --git a/tests/tests/media/AndroidTest.xml b/tests/tests/media/AndroidTest.xml
index d370d38..03d4770 100644
--- a/tests/tests/media/AndroidTest.xml
+++ b/tests/tests/media/AndroidTest.xml
@@ -26,6 +26,8 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.cts" />
+ <!-- setup can be expensive so limit the number of shards -->
+ <option name="ajur-max-shard" value="5" />
<!-- test-timeout unit is ms, value = 30 min -->
<option name="test-timeout" value="1800000" />
<option name="runtime-hint" value="4h" />
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
index 6cf9a89..28c528c 100644
--- a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -64,6 +64,8 @@
0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b
};
+// The test content is not packaged with clearkey UUID,
+// we have to use a canned clearkey pssh for the test.
static const uint8_t kClearkeyPssh[] = {
// BMFF box header (4 bytes size + 'pssh')
0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index fd8c3b1..c401c75 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -300,6 +300,24 @@
mSubscriptionCallback.mLastOptions.getInt(MediaBrowser.EXTRA_PAGE_SIZE));
}
+ public void testSubscriptionCallbackNotCalledAfterDisconnect() {
+ createMediaBrowser(TEST_BROWSER_SERVICE);
+ connectMediaBrowserService();
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ mMediaBrowser.disconnect();
+ resetCallbacks();
+ StubMediaBrowserService.sInstance.notifyChildrenChanged(
+ StubMediaBrowserService.MEDIA_ID_ROOT);
+ try {
+ Thread.sleep(SLEEP_MS);
+ } catch (InterruptedException e) {
+ fail("Unexpected InterruptedException occurred.");
+ }
+ assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
+ assertEquals(0, mSubscriptionCallback.mChildrenLoadedWithOptionCount);
+ assertNull(mSubscriptionCallback.mLastParentId);
+ }
+
public void testUnsubscribeForMultipleSubscriptions() {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
@@ -436,6 +454,21 @@
assertEquals(StubMediaBrowserService.MEDIA_ID_INVALID, mItemCallback.mLastErrorId);
}
+ public void testItemCallbackNotCalledAfterDisconnect() {
+ createMediaBrowser(TEST_BROWSER_SERVICE);
+ connectMediaBrowserService();
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ mMediaBrowser.disconnect();
+ resetCallbacks();
+ try {
+ Thread.sleep(SLEEP_MS);
+ } catch (InterruptedException e) {
+ fail("Unexpected InterruptedException occurred.");
+ }
+ assertNull(mItemCallback.mLastMediaItem);
+ assertNull(mItemCallback.mLastErrorId);
+ }
+
private void createMediaBrowser(final ComponentName component) {
getInstrumentation().runOnMainSync(new Runnable() {
@Override
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
index 2375d46..f6d5e83 100644
--- a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -153,6 +153,7 @@
try {
testGetPropertyStringNative(uuidByteArray(CLEARKEY_SCHEME_UUID),
"unknown-property", value);
+ fail("Should have thrown an exception");
} catch (RuntimeException e) {
Log.e(TAG, "testUnknownPropertyString error = '" + e.getMessage() + "'");
assertThat(e.getMessage(), containsString("get property string returns"));
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index 66acd71..2017eba 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -1,4 +1,4 @@
-# Copyright 2017 The Android Open Source Project
+# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,39 +12,30 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Build the unit tests.
-
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := CtsNativeMediaAAudioTestCases
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+
+LOCAL_PACKAGE_NAME := CtsNativeMediaAAudioTestCases
+
+# Include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_SRC_FILES := \
- src/test_aaudio.cpp \
- src/test_aaudio_misc.cpp \
- src/test_aaudio_callback.cpp \
- src/test_aaudio_stream_builder.cpp \
- src/utils.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libaaudio \
- liblog \
-
-LOCAL_STATIC_LIBRARIES := \
- libgtest_ndk_c++ \
-
-LOCAL_CTS_TEST_PACKAGE := android.nativemedia.aaudio
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_CFLAGS := -Werror -Wall
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner nativetesthelper
+
+LOCAL_JNI_SHARED_LIBRARIES := libnativeaaudiotest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
-LOCAL_NDK_STL_VARIANT := c++_static
-include $(BUILD_CTS_EXECUTABLE)
+include $(BUILD_CTS_PACKAGE)
+
+# Include the associated library's makefile.
+include $(LOCAL_PATH)/jni/Android.mk
diff --git a/tests/tests/nativemedia/aaudio/AndroidManifest.xml b/tests/tests/nativemedia/aaudio/AndroidManifest.xml
new file mode 100644
index 0000000..97bf5f9
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.nativemedia.aaudio">
+
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- This is a self-instrumenting test package. -->
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.nativemedia.aaudio"
+ android:label="CTS tests of native AAudio API">
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/nativemedia/aaudio/AndroidTest.xml b/tests/tests/nativemedia/aaudio/AndroidTest.xml
index 7030d0c..b796ea6 100644
--- a/tests/tests/nativemedia/aaudio/AndroidTest.xml
+++ b/tests/tests/nativemedia/aaudio/AndroidTest.xml
@@ -15,16 +15,14 @@
-->
<configuration description="Config for CTS Native Media AAudio test cases">
<option name="config-descriptor:metadata" key="component" value="media" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsNativeMediaAAudioTestCases->/data/local/tmp/CtsNativeMediaAAudioTestCases" />
- <option name="append-bitness" value="true" />
+ <option name="test-suite-tag" value="cts" />
+ <option name="not-shardable" value="true" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsNativeMediaAAudioTestCases.apk" />
</target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsNativeMediaAAudioTestCases" />
- <option name="runtime-hint" value="2m" />
- <!-- test-timeout unit is ms, value = 2 min -->
- <option name="native-test-timeout" value="120000" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.nativemedia.aaudio" />
+ <option name="runtime-hint" value="2m0s" />
</test>
</configuration>
diff --git a/tests/tests/nativemedia/aaudio/jni/Android.mk b/tests/tests/nativemedia/aaudio/jni/Android.mk
new file mode 100644
index 0000000..8ef7aac
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/jni/Android.mk
@@ -0,0 +1,41 @@
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libnativeaaudiotest
+LOCAL_MULTILIB := both
+
+LOCAL_SRC_FILES := \
+ test_aaudio.cpp \
+ test_aaudio_misc.cpp \
+ test_aaudio_callback.cpp \
+ test_aaudio_stream_builder.cpp \
+ utils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libaaudio \
+ liblog
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libnativetesthelper_jni
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.h b/tests/tests/nativemedia/aaudio/jni/test_aaudio.h
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio.h
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio.h
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_callback.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_callback.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_misc.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_misc.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_stream_builder.cpp b/tests/tests/nativemedia/aaudio/jni/test_aaudio_stream_builder.cpp
similarity index 100%
rename from tests/tests/nativemedia/aaudio/src/test_aaudio_stream_builder.cpp
rename to tests/tests/nativemedia/aaudio/jni/test_aaudio_stream_builder.cpp
diff --git a/tests/tests/nativemedia/aaudio/src/utils.cpp b/tests/tests/nativemedia/aaudio/jni/utils.cpp
similarity index 92%
rename from tests/tests/nativemedia/aaudio/src/utils.cpp
rename to tests/tests/nativemedia/aaudio/jni/utils.cpp
index 8b9f60d..d1a3115 100644
--- a/tests/tests/nativemedia/aaudio/src/utils.cpp
+++ b/tests/tests/nativemedia/aaudio/jni/utils.cpp
@@ -161,22 +161,6 @@
: StreamBuilderHelper{AAUDIO_DIRECTION_INPUT,
48000, 1, AAUDIO_FORMAT_PCM_I16, requestedSharingMode, requestedPerfMode} {}
-// Native apps don't have permissions, thus recording can
-// only be tested when running as root.
-static bool canTestRecording() {
- static const bool runningAsRoot = getuid() == 0;
- return runningAsRoot;
-}
-
-void InputStreamBuilderHelper::createAndVerifyStream(bool *success) {
- if (!canTestRecording()) {
- __android_log_write(ANDROID_LOG_WARN, LOG_TAG, "No permissions to run recording tests");
- *success = false;
- } else {
- StreamBuilderHelper::createAndVerifyStream(success);
- }
-}
-
OutputStreamBuilderHelper::OutputStreamBuilderHelper(
aaudio_sharing_mode_t requestedSharingMode, aaudio_performance_mode_t requestedPerfMode)
diff --git a/tests/tests/nativemedia/aaudio/src/utils.h b/tests/tests/nativemedia/aaudio/jni/utils.h
similarity index 98%
rename from tests/tests/nativemedia/aaudio/src/utils.h
rename to tests/tests/nativemedia/aaudio/jni/utils.h
index fbb3e76..77bbc52 100644
--- a/tests/tests/nativemedia/aaudio/src/utils.h
+++ b/tests/tests/nativemedia/aaudio/jni/utils.h
@@ -81,7 +81,6 @@
InputStreamBuilderHelper(
aaudio_sharing_mode_t requestedSharingMode,
aaudio_performance_mode_t requestedPerfMode);
- void createAndVerifyStream(bool *success);
};
class OutputStreamBuilderHelper : public StreamBuilderHelper {
diff --git a/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java b/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java
new file mode 100644
index 0000000..afb2db4
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/android/nativemedia/aaudio/AAudioTests.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nativemedia.aaudio;
+
+import org.junit.runner.RunWith;
+import com.android.gtestrunner.GtestRunner;
+import com.android.gtestrunner.TargetLibrary;
+
+@RunWith(GtestRunner.class)
+@TargetLibrary("nativeaaudiotest")
+public class AAudioTests {}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index cd6dbb2..1396a1c 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,8 +16,11 @@
package android.net.cts;
+import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.PendingIntent;
@@ -29,6 +32,7 @@
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
@@ -49,14 +53,23 @@
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.Inet6Address;
+import java.net.InetAddress;
import java.net.Socket;
import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import libcore.io.Streams;
public class ConnectivityManagerTest extends AndroidTestCase {
@@ -106,6 +119,8 @@
private final HashMap<Integer, NetworkConfig> mNetworks =
new HashMap<Integer, NetworkConfig>();
boolean mWifiConnectAttempted;
+ private TestNetworkCallback mCellNetworkCallback;
+
@Override
protected void setUp() throws Exception {
@@ -138,6 +153,10 @@
if (mWifiConnectAttempted) {
disconnectFromWifi(null);
}
+ if (cellConnectAttempted()) {
+ disconnectFromCell();
+ }
+ super.tearDown();
}
/**
@@ -244,6 +263,95 @@
}
}
+ /**
+ * Tests that connections can be opened on WiFi and cellphone networks,
+ * and that they are made from different IP addresses.
+ */
+ public void testOpenConnection() throws Exception {
+ boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI)
+ && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
+ if (!canRunTest) {
+ Log.i(TAG,"testOpenConnection cannot execute unless device supports both WiFi "
+ + "and a cellular connection");
+ return;
+ }
+
+ Network wifiNetwork = connectToWifi();
+ Network cellNetwork = connectToCell();
+ // This server returns the requestor's IP address as the response body.
+ URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
+ String wifiAddressString = httpGet(wifiNetwork, url);
+ String cellAddressString = httpGet(cellNetwork, url);
+
+ assertFalse(String.format("Same address '%s' on two different networks (%s, %s)",
+ wifiAddressString, wifiNetwork, cellNetwork),
+ wifiAddressString.equals(cellAddressString));
+
+ // Sanity check that the IP addresses that the requests appeared to come from
+ // are actually on the respective networks.
+ assertOnNetwork(wifiAddressString, wifiNetwork);
+ assertOnNetwork(cellAddressString, cellNetwork);
+
+ assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
+ }
+
+ private Network connectToCell() throws InterruptedException {
+ if (cellConnectAttempted()) {
+ throw new IllegalStateException("Already connected");
+ }
+ NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ mCellNetworkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(cellRequest, mCellNetworkCallback);
+ final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
+ assertNotNull("Cell network not available within timeout", cellNetwork);
+ return cellNetwork;
+ }
+
+ private boolean cellConnectAttempted() {
+ return mCellNetworkCallback != null;
+ }
+
+ private void disconnectFromCell() {
+ if (!cellConnectAttempted()) {
+ throw new IllegalStateException("Cell connection not attempted");
+ }
+ mCm.unregisterNetworkCallback(mCellNetworkCallback);
+ mCellNetworkCallback = null;
+ }
+
+ /**
+ * Performs a HTTP GET to the specified URL on the specified Network, and returns
+ * the response body decoded as UTF-8.
+ */
+ private static String httpGet(Network network, URL httpUrl) throws IOException {
+ HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
+ try {
+ InputStream inputStream = connection.getInputStream();
+ return Streams.readFully(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ } finally {
+ connection.disconnect();
+ }
+ }
+
+ private void assertOnNetwork(String adressString, Network network) throws UnknownHostException {
+ InetAddress address = InetAddress.getByName(adressString);
+ LinkProperties linkProperties = mCm.getLinkProperties(network);
+ // To make sure that the request went out on the right network, check that
+ // the IP address seen by the server is assigned to the expected network.
+ // We can only do this for IPv6 addresses, because in IPv4 we will likely
+ // have a private IPv4 address, and that won't match what the server sees.
+ if (address instanceof Inet6Address) {
+ assertContains(linkProperties.getAddresses(), address);
+ }
+ }
+
+ private static<T> void assertContains(Collection<T> collection, T element) {
+ assertTrue(element + " not found in " + collection, collection.contains(element));
+ }
+
private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
try {
mCm.startUsingNetworkFeature(networkType, feature);
@@ -323,7 +431,7 @@
* that it would increase test coverage by much (how many devices have 3G radio but not Wifi?).
*/
public void testRegisterNetworkCallback() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
return;
}
@@ -363,7 +471,7 @@
* of a {@code NetworkCallback}.
*/
public void testRegisterNetworkCallback_withPendingIntent() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi");
return;
}
@@ -457,7 +565,7 @@
* Tests reporting of connectivity changed.
*/
public void testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testConnectivityChanged_manifestRequestOnly_shouldNotReceiveIntent cannot execute unless device supports WiFi");
return;
}
@@ -474,7 +582,7 @@
}
public void testConnectivityChanged_whenRegistered_shouldReceiveIntent() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testConnectivityChanged_whenRegistered_shouldReceiveIntent cannot execute unless device supports WiFi");
return;
}
@@ -494,7 +602,7 @@
public void testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent()
throws InterruptedException {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
Log.i(TAG, "testConnectivityChanged_manifestRequestOnlyPreN_shouldReceiveIntent cannot execute unless device supports WiFi");
return;
}
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
index 4c68423..b45bfe0 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -23,9 +23,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
ctstestserver \
- org.apache.http.legacy \
legacy-android-test
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficFalseTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
index 49385f8..d4ce39a 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
index 584afd2..89195cd 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -23,9 +23,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
ctstestserver \
- org.apache.http.legacy \
legacy-android-test
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficTrueTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
index be698f2..fe31e80 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
index 9a613e7..bad2cbc 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -23,9 +23,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
ctstestserver \
- org.apache.http.legacy \
legacy-android-test
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
LOCAL_SRC_FILES := $(call all-java-files-under, src common)
LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficUnspecifiedTestCases
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
index 7bd8742..c6b65c0 100644
--- a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
index 10018ce..4af2de7 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
index 9356074..972052e 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-attributes/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigAttributeTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
index 161dbd3..95e14ef 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
index 565f23a..3e5fe25 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-basic-domain/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigBasicDomainConfigTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
index 927374c..278d634 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
index b387ffa..8ee5482 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-cleartext/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigCleartextTrafficTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
index aa0eefd..fd5f419 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
@@ -31,4 +33,4 @@
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
LOCAL_SDK_VERSION := current
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
index 3f15f81..28bba5b 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-disabled/AndroidManifest.xml
@@ -21,6 +21,7 @@
<application android:debuggable="false"
android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
index be9174e..d808928 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
index 6d98702..b667271 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-debug-basic-enabled/AndroidManifest.xml
@@ -21,6 +21,7 @@
<application android:debuggable="true"
android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
index 84e72b0..54727c6 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/Android.mk
@@ -22,10 +22,11 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
- org.apache.http.legacy \
android-support-test \
legacy-android-test
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
index e18ff4d..cc67cca 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-downloadmanager/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigDownloadManagerTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
index 4764cab..3d66c53 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
index b3b32b5..bf6e369 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-invalid-pin/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigInvalidPinTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
index 5448f34..e96ae6a 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/Android.mk
@@ -20,7 +20,9 @@
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner org.apache.http.legacy android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
index 1790150..75247d3 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-nested-domains/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigNestedDomainConfigTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
index 924f393..4e7efdeb 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/Android.mk
@@ -22,10 +22,11 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ctstestrunner \
- org.apache.http.legacy \
android-support-test \
legacy-android-test
+LOCAL_JAVA_LIBRARIES := org.apache.http.legacy
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, ../src)
diff --git a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
index 46787160..4884458 100644
--- a/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
+++ b/tests/tests/networksecurityconfig/networksecurityconfig-resourcesrc/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="android.security.net.config.cts.CtsNetSecConfigResourcesSrcTestCases">
<application android:networkSecurityConfig="@xml/network_security_config">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="org.apache.http.legacy" />
</application>
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
index 4225de0..24b0f6a 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -191,7 +191,7 @@
"EGL_KHR_wait_sync",
};
- for (int i = 0; i < requiredList.length; ++i) {
+ for (int i = 0; i < requiredEglList.length; ++i) {
assertTrue("Required EGL extension for VR high-performance is missing: " +
requiredEglList[i], hasExtension(extensions, requiredEglList[i]));
}
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index 8104cab..52c184f 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1 +1 @@
-8.1.0
+P
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index a820ac0..676465e 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -617,6 +617,38 @@
looperThread.join();
}
+ public void testOpenProxyFileDescriptor_largeFile() throws Exception {
+ final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
+ @Override
+ public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+ for (int i = 0; i < size; i++) {
+ data[i] = 'L';
+ }
+ return size;
+ }
+
+ @Override
+ public long onGetSize() throws ErrnoException {
+ return 8L * 1024L * 1024L * 1024L; // 8GB
+ }
+
+ @Override
+ public void onRelease() {}
+ };
+ final byte[] bytes = new byte[128];
+ try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
+ ParcelFileDescriptor.MODE_READ_ONLY, callback)) {
+ assertEquals(8L * 1024L * 1024L * 1024L, fd.getStatSize());
+
+ final int readBytes = Os.pread(
+ fd.getFileDescriptor(), bytes, 0, bytes.length, fd.getStatSize() - 64L);
+ assertEquals(64, readBytes);
+ for (int i = 0; i < 64; i++) {
+ assertEquals('L', bytes[i]);
+ }
+ }
+ }
+
private void assertStorageVolumesEquals(StorageVolume volume, StorageVolume clone)
throws Exception {
// Asserts equals() method.
diff --git a/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java b/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
index 921f5f1..06e858e 100644
--- a/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
+++ b/tests/tests/packageinstaller/externalsources/src/android/packageinstaller/externalsources/cts/ExternalSourcesTest.java
@@ -41,7 +41,6 @@
private PackageManager mPm;
private String mPackageName;
private UiDevice mUiDevice;
- private boolean mHasFeature;
@Before
public void setUp() throws Exception {
@@ -49,7 +48,6 @@
mPm = mContext.getPackageManager();
mPackageName = mContext.getPackageName();
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- mHasFeature = !mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
}
private void setAppOpsMode(String mode) throws IOException {
@@ -86,9 +84,6 @@
@Test
public void testManageUnknownSourcesExists() {
- if (!mHasFeature) {
- return;
- }
Intent manageUnknownSources = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
ResolveInfo info = mPm.resolveActivity(manageUnknownSources, 0);
Assert.assertNotNull("No activity found for " + manageUnknownSources.getAction(), info);
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index ebcd41e..f77c9b3 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -510,6 +510,23 @@
mCreateActivityCallCounter.reset();
}
+ /**
+ * Wait until the message is shown that indicates that a printer is unavailable.
+ *
+ * @throws Exception If anything was unexpected.
+ */
+ protected void waitForPrinterUnavailable() throws Exception {
+ final String printerUnavailableMessage =
+ getPrintSpoolerString("print_error_printer_unavailable");
+
+ UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/message"));
+ if (!message.getText().equals(printerUnavailableMessage)) {
+ throw new Exception("Wrong message: " + message.getText() + " instead of "
+ + printerUnavailableMessage);
+ }
+ }
+
void selectPrinter(String printerName) throws UiObjectNotFoundException, IOException {
try {
long delay = 1;
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
index c3e6e96..486d6e4 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
@@ -42,6 +42,12 @@
}
BasePrintTest.onActivityCreateCalled(mTestId, this);
+
+ if (savedInstanceState != null) {
+ Log.d(LOG_TAG,
+ "We cannot deal with lifecycle. Hence finishing " + this + " for " + mTestId);
+ finish();
+ }
}
@Override
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
index 9b277e9..d391bd2 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesChangeTest.java
@@ -16,6 +16,8 @@
package android.print.cts;
+import static android.print.cts.Utils.runOnMainThread;
+
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -34,9 +36,8 @@
import android.print.cts.services.PrinterDiscoverySessionCallbacks;
import android.print.cts.services.SecondPrintService;
import android.print.cts.services.StubbablePrinterDiscoverySession;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
import android.util.Log;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,8 +48,6 @@
import java.util.List;
import java.util.concurrent.TimeoutException;
-import static android.print.cts.Utils.runOnMainThread;
-
/**
* This test verifies changes to the printer capabilities are applied correctly.
*/
@@ -154,23 +153,6 @@
PrinterInfo.STATUS_UNAVAILABLE)));
}
- /**
- * Wait until the message is shown that indicates that a printer is unavilable.
- *
- * @throws Exception If anything was unexpected.
- */
- private void waitForPrinterUnavailable() throws Exception {
- final String PRINTER_UNAVAILABLE_MSG =
- getPrintSpoolerString("print_error_printer_unavailable");
-
- UiObject message = getUiDevice().findObject(new UiSelector().resourceId(
- "com.android.printspooler:id/message"));
- if (!message.getText().equals(PRINTER_UNAVAILABLE_MSG)) {
- throw new Exception("Wrong message: " + message.getText() + " instead of " +
- PRINTER_UNAVAILABLE_MSG);
- }
- }
-
@Before
public void setUpPrinting() throws Exception {
// Create the mSession[0] callbacks that we will be checking.
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index 499d21e..c90b9e6 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -16,8 +16,13 @@
package android.print.cts;
-import static android.print.cts.Utils.*;
-import static org.junit.Assert.*;
+import static android.print.cts.Utils.eventually;
+import static android.print.cts.Utils.runOnMainThread;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.inOrder;
import android.print.PrintAttributes;
@@ -35,8 +40,11 @@
import android.print.cts.services.StubbablePrinterDiscoverySession;
import android.printservice.PrintJob;
import android.printservice.PrinterDiscoverySession;
-
+import android.support.annotation.NonNull;
import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,10 +61,7 @@
*/
@RunWith(AndroidJUnit4.class)
public class PrinterDiscoverySessionLifecycleTest extends BasePrintTest {
- private static final String FIRST_PRINTER_NAME = "First printer";
- private static final String SECOND_PRINTER_NAME = "Second printer";
-
- private static final String FIRST_PRINTER_LOCAL_ID= "first_printer";
+ private static final String FIRST_PRINTER_LOCAL_ID = "first_printer";
private static final String SECOND_PRINTER_LOCAL_ID = "second_printer";
private static StubbablePrinterDiscoverySession sSession;
@@ -66,6 +71,172 @@
clearPrintSpoolerData();
}
+ /**
+ * Add a printer to {@#sSession}.
+ *
+ * @param localId The id of the printer to add
+ * @param hasCapabilities If the printer has capabilities
+ */
+ private void addPrinter(@NonNull String localId, boolean hasCapabilities) {
+ // Add the first printer.
+ PrinterId firstPrinterId = sSession.getService().generatePrinterId(
+ localId);
+
+ PrinterInfo.Builder printer = new PrinterInfo.Builder(firstPrinterId,
+ localId, PrinterInfo.STATUS_IDLE);
+
+ if (hasCapabilities) {
+ printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+ .setMinMargins(new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A0, true)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build());
+ }
+
+ sSession.addPrinters(Collections.singletonList(printer.build()));
+ }
+
+ /**
+ * Make {@code localPrinterId} the default printer. This requires a full print workflow.
+ *
+ * As a side-effect also approved the print service.
+ *
+ * @param localPrinterId The printer to make default
+ */
+ private void makeDefaultPrinter(String localPrinterId) throws Throwable {
+ PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+
+ print(adapter);
+ waitForWriteAdapterCallback(1);
+
+ runOnMainThread(() -> addPrinter(localPrinterId, true));
+ selectPrinter(localPrinterId);
+ waitForWriteAdapterCallback(2);
+
+ clickPrintButton();
+ answerPrintServicesWarning(true);
+
+ waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+ resetCounters();
+ }
+
+ /**
+ * Select a printer in the all printers activity
+ *
+ * @param printerName The name of the printer to select
+ */
+ private void selectInAllPrintersActivity(@NonNull String printerName) throws Exception {
+ while (true) {
+ UiObject printerItem = getUiDevice().findObject(
+ new UiSelector().text(printerName));
+
+ if (printerItem.isEnabled()) {
+ printerItem.click();
+ break;
+ } else {
+ Thread.sleep(100);
+ }
+ }
+ }
+
+ @Test
+ public void defaultPrinterBecomesAvailableWhileInBackground() throws Throwable {
+ // Create the session callbacks that we will be checking.
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(invocation -> {
+ sSession =
+ ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+ onPrinterDiscoverySessionCreateCalled();
+ return null;
+ }, null, null, null, null, null, invocation -> {
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ });
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ invocation -> firstSessionCallbacks, null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID);
+
+ PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+ print(adapter);
+ waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+ waitForPrinterUnavailable();
+
+ selectPrinter("All printers…");
+ // Let all printers activity start
+ Thread.sleep(500);
+
+ // Add printer
+ runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true));
+
+ // Select printer once available (this returns to main print activity)
+ selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID);
+
+ // Wait for preview to load and finish print
+ waitForWriteAdapterCallback(1);
+ clickPrintButton();
+ waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+ }
+
+ @Test
+ public void defaultPrinterBecomesUsableWhileInBackground() throws Throwable {
+ // Create the session callbacks that we will be checking.
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(invocation -> {
+ sSession =
+ ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+ onPrinterDiscoverySessionCreateCalled();
+ return null;
+ }, null, null, null, null, null, invocation -> {
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ });
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ invocation -> firstSessionCallbacks, null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID);
+
+ PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
+ print(adapter);
+ waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+ // Add printer but do not enable it (capabilities == null)
+ runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, false));
+ waitForPrinterUnavailable();
+
+ selectPrinter("All printers…");
+ // Let all printers activity start
+ Thread.sleep(500);
+
+ // Enable printer
+ runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true));
+
+ // Select printer once available (this returns to main print activity)
+ selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID);
+
+ // Wait for preview to load and finish print
+ waitForWriteAdapterCallback(1);
+ clickPrintButton();
+ waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
+ }
+
@Test
public void normalLifecycle() throws Throwable {
// Create the session callbacks that we will be checking.
@@ -99,7 +270,7 @@
runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
// Select the first printer.
- selectPrinter(FIRST_PRINTER_NAME);
+ selectPrinter(FIRST_PRINTER_LOCAL_ID);
eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -111,7 +282,7 @@
// Select the second printer (same capabilities as the other
// one so no layout should happen).
- selectPrinter(SECOND_PRINTER_NAME);
+ selectPrinter(SECOND_PRINTER_LOCAL_ID);
eventually(() -> runOnMainThread(() -> assertEquals(SECOND_PRINTER_LOCAL_ID,
sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -205,7 +376,7 @@
runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
// Select the first printer.
- selectPrinter(FIRST_PRINTER_NAME);
+ selectPrinter(FIRST_PRINTER_LOCAL_ID);
eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -295,7 +466,7 @@
runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
// Select the first printer.
- selectPrinter(FIRST_PRINTER_NAME);
+ selectPrinter(FIRST_PRINTER_LOCAL_ID);
eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID,
sSession.getTrackedPrinters().get(0).getLocalId())));
@@ -491,27 +662,9 @@
assertTrue(sSession.isPrinterDiscoveryStarted());
- if (sSession.getPrinters().isEmpty()) {
- List<PrinterInfo> printers = new ArrayList<>();
+ addPrinter(FIRST_PRINTER_LOCAL_ID, false);
+ addPrinter(SECOND_PRINTER_LOCAL_ID, false);
- // Add the first printer.
- PrinterId firstPrinterId = sSession.getService().generatePrinterId(
- FIRST_PRINTER_LOCAL_ID);
- PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
- FIRST_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
- .build();
- printers.add(firstPrinter);
-
- // Add the first printer.
- PrinterId secondPrinterId = sSession.getService().generatePrinterId(
- SECOND_PRINTER_LOCAL_ID);
- PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
- SECOND_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
- .build();
- printers.add(secondPrinter);
-
- sSession.addPrinters(printers);
- }
return null;
}, invocation -> {
assertFalse(sSession.isPrinterDiscoveryStarted());
diff --git a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
index 3b38aba..c408d92 100644
--- a/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
+++ b/tests/tests/proto/src/android/util/proto/cts/ProtoOutputStreamTagTest.java
@@ -92,6 +92,7 @@
// Try it in the provided name
try {
ProtoOutputStream.checkFieldId(42 | goodCount | badType, goodCount | fieldType);
+ fail("Should have thrown an exception.");
} catch (IllegalArgumentException ex) {
assertEquals("writeRepeated" + string
+ " called for field 42 which should be used"
@@ -102,6 +103,7 @@
// Try it in the expected name
try {
ProtoOutputStream.checkFieldId(43 | goodCount | fieldType, goodCount | badType);
+ fail("Should have thrown an exception.");
} catch (IllegalArgumentException ex) {
assertEquals("writeRepeated" + badTypeString
+ " called for field 43 which should be used"
@@ -126,6 +128,7 @@
// Try it in the provided name
try {
ProtoOutputStream.checkFieldId(44 | badCount | goodType, fieldCount | goodType);
+ fail("Should have thrown an exception.");
} catch (IllegalArgumentException ex) {
assertEquals("write" + string
+ "Fixed32 called for field 44 which should be used"
@@ -136,6 +139,7 @@
// Try it in the expected name
try {
ProtoOutputStream.checkFieldId(45 | fieldCount | goodType, badCount | goodType);
+ fail("Should have thrown an exception.");
} catch (IllegalArgumentException ex) {
String extraString = "";
if (fieldCount == ProtoOutputStream.FIELD_COUNT_PACKED) {
@@ -151,7 +155,7 @@
/**
* Validate one call to checkFieldId that is expected to throw.
*/
- public void assertCheckFieldIdThrows(long fieldId, long expectedFlags)
+ public void assertCheckFieldIdThrows(long fieldId, long expectedFlags)
throws Exception {
try {
ProtoOutputStream.checkFieldId(fieldId, expectedFlags);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
index 9b355b0..ab326ff 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/refocus/RefocusTest.java
@@ -37,14 +37,14 @@
/**
* Test the orignal refocus code
*/
- public void testOriginalRefocus() {
+ public void testOriginalRefocus() throws IOException {
refocus(RenderScriptTask.script.f32, 95);
}
/**
* Test the new refocus code
*/
- public void testNewRefocus() {
+ public void testNewRefocus() throws IOException {
// The new implementation may run on a GPU using relaxed floating point
// mathematics. Hence more relaxed precision requirement.
refocus(RenderScriptTask.script.d1new, 45);
@@ -54,7 +54,7 @@
* Test a refocus operator against the refocus_reference image
* @param impl version of refocus to run
*/
- private void refocus(RenderScriptTask.script impl, double minimumPSNR) {
+ private void refocus(RenderScriptTask.script impl, double minimumPSNR) throws IOException {
Context ctx = getContext();
RenderScript rs = RenderScript.create(ctx);
@@ -63,27 +63,26 @@
current_rgbz = new RGBZ(getResourceRef(R.drawable.test_image),
getResourceRef(R.drawable.test_depthmap),
ctx.getContentResolver(), ctx);
- } catch (IOException e) {
- e.printStackTrace();
- assertNull(e);
+ DepthOfFieldOptions current_depth_options = new DepthOfFieldOptions(current_rgbz);
+ RsTaskParams rsTaskParam = new RsTaskParams(rs, current_depth_options);
+
+ RenderScriptTask renderScriptTask = new RenderScriptTask(rs, impl);
+ Bitmap outputImage = renderScriptTask.applyRefocusFilter(rsTaskParam.mOptions);
+
+ Bitmap expectedImage = BitmapFactory.decodeResource(ctx.getResources(),
+ R.drawable.expected_output);
+
+ double psnr = ImageCompare.psnr(outputImage, expectedImage);
+ android.util.Log.i("RefocusTest", "psnr = " + String.format("%.02f", psnr));
+ if (psnr < minimumPSNR) {
+ MediaStoreSaver.savePNG(outputImage, "refocus", "refocus_output" , ctx);
+ assertTrue("Required minimum psnr = " + String.format("%.02f; ", minimumPSNR) +
+ "Actual psnr = " + String.format("%.02f", psnr),
+ false);
+ }
+ } finally {
+ rs.destroy();
}
- DepthOfFieldOptions current_depth_options = new DepthOfFieldOptions(current_rgbz);
- RsTaskParams rsTaskParam = new RsTaskParams(rs, current_depth_options);
-
- RenderScriptTask renderScriptTask = new RenderScriptTask(rs, impl);
- Bitmap outputImage = renderScriptTask.applyRefocusFilter(rsTaskParam.mOptions);
-
- Bitmap expectedImage = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.expected_output);
-
- double psnr = ImageCompare.psnr(outputImage, expectedImage);
- android.util.Log.i("RefocusTest", "psnr = " + String.format("%.02f", psnr));
- if (psnr < minimumPSNR) {
- MediaStoreSaver.savePNG(outputImage, "refocus", "refocus_output" , ctx);
- assertTrue("Required minimum psnr = " + String.format("%.02f; ", minimumPSNR) +
- "Actual psnr = " + String.format("%.02f", psnr),
- false);
- }
- rs.destroy();
}
diff --git a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
index 857ffd8..6b3abf6 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/StubTextToSpeechService.java
@@ -15,6 +15,7 @@
*/
package android.speech.tts.cts;
+import android.os.ConditionVariable;
import android.media.AudioFormat;
import android.os.ConditionVariable;
import android.speech.tts.SynthesisCallback;
@@ -37,6 +38,10 @@
// Object that onSynthesizeText will #block on, if set to non-null
public static volatile ConditionVariable sSynthesizeTextWait;
+ // Condition variable that onSynthesizeText will #open when it started
+ // synethesizing, if set to non-null.
+ public static volatile ConditionVariable sSynthesizeTextStartEvent;
+
private ArrayList<Locale> supportedLanguages = new ArrayList<Locale>();
private ArrayList<Locale> supportedCountries = new ArrayList<Locale>();
private ArrayList<Locale> GBFallbacks = new ArrayList<Locale>();
@@ -80,6 +85,11 @@
return;
}
+ final ConditionVariable synthesizeTextStartEvent = sSynthesizeTextStartEvent;
+ if (synthesizeTextStartEvent != null) {
+ sSynthesizeTextStartEvent.open();
+ }
+
final ConditionVariable synthesizeTextWait = sSynthesizeTextWait;
if (synthesizeTextWait != null) {
synthesizeTextWait.block(10000); // 10s timeout
diff --git a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
index 4d9faad..8e54d31 100644
--- a/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
+++ b/tests/tests/speech/src/android/speech/tts/cts/TextToSpeechServiceTest.java
@@ -117,6 +117,27 @@
}
}
+ public void testSpeakStopBehindOtherAudioPlayback() throws Exception {
+ final ConditionVariable synthesizeTextWait = new ConditionVariable();
+ final ConditionVariable synthesizeTextStartEvent = new ConditionVariable();
+ StubTextToSpeechService.sSynthesizeTextWait = synthesizeTextWait;
+ StubTextToSpeechService.sSynthesizeTextStartEvent = synthesizeTextStartEvent;
+
+ // Make the audio playback queue busy by putting a 30s of silence.
+ getTts().stop();
+ getTts().playSilentUtterance(30000, TextToSpeech.QUEUE_ADD, "silence");
+
+ // speak(), wait it to starting in the service, and stop().
+ int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_ADD, null, "stop");
+ assertEquals("speak() failed", TextToSpeech.SUCCESS, result);
+ assertTrue("synthesis not started", synthesizeTextStartEvent.block(10000));
+ getTts().stop();
+
+ // Wake up the Stubs #onSynthesizeSpeech (one that will be stopped in-progress)
+ synthesizeTextWait.open();
+
+ assertTrue("speak() stop callback timeout", mTts.waitForStop("stop"));
+ }
public void testMediaPlayerFails() throws Exception {
File sampleFile = new File(Environment.getExternalStorageDirectory(), "notsound.wav");
diff --git a/tests/tests/systemintents/Android.mk b/tests/tests/systemintents/Android.mk
index 573e2ee..77b28a4 100644
--- a/tests/tests/systemintents/Android.mk
+++ b/tests/tests/systemintents/Android.mk
@@ -27,7 +27,7 @@
LOCAL_PACKAGE_NAME := CtsSystemIntentTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner legacy-android-test android-support-test
LOCAL_SDK_VERSION := test_current
diff --git a/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java b/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
index c572629..086f2cb 100644
--- a/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
+++ b/tests/tests/systemintents/src/android/systemintents/cts/TestSystemIntents.java
@@ -16,6 +16,8 @@
package android.systemintents.cts;
+import static org.junit.Assert.assertTrue;
+
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -23,14 +25,17 @@
import android.net.Uri;
import android.provider.Settings;
import android.support.test.filters.MediumTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
import android.util.Log;
-import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
@MediumTest
-public class TestSystemIntents extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TestSystemIntents {
+
/*
* List of activity intents defined by the system. Activities to handle each of these
* intents must all exist.
@@ -56,7 +61,6 @@
}
}
- @Rule
private final IntentEntry[] mTestIntents = {
/* Settings-namespace intent actions */
new IntentEntry(0, new Intent(Settings.ACTION_SETTINGS)),
@@ -76,7 +80,7 @@
@Test
public void testSystemIntents() {
- final PackageManager pm = getContext().getPackageManager();
+ final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
int productFlags = 0;
if (pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
@@ -87,7 +91,7 @@
productFlags |= EXCLUDE_NON_TELEPHONY;
}
- final Configuration config = getContext().getResources().getConfiguration();
+ final Configuration config = InstrumentationRegistry.getContext().getResources().getConfiguration();
if ((config.uiMode & Configuration.UI_MODE_TYPE_WATCH) != 0) {
productFlags |= EXCLUDE_WATCH;
}
@@ -99,4 +103,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index fc0d841..453640d 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -23,6 +23,8 @@
<application>
<activity android:name=".LightBarActivity"
android:theme="@android:style/Theme.Material.NoActionBar"></activity>
+ <activity android:name=".LightBarThemeActivity"
+ android:theme="@style/LightBarTheme"></activity>
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/systemui/res/values/styles.xml b/tests/tests/systemui/res/values/styles.xml
new file mode 100644
index 0000000..e3e8a01
--- /dev/null
+++ b/tests/tests/systemui/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <style name="LightBarTheme" parent="@android:style/Theme.Material.Light.NoActionBar">
+ <item name="android:windowLightStatusBar">true</item>
+ <item name="android:windowLightNavigationBar">true</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java
new file mode 100644
index 0000000..4ae2e35
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.systemui.cts;
+
+import android.app.Activity;
+
+public class LightBarThemeActivity extends Activity {
+}
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
new file mode 100644
index 0000000..9fc6d58
--- /dev/null
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.systemui.cts;
+
+import android.os.SystemClock;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class LightBarThemeTest {
+
+ @Rule
+ public ActivityTestRule<LightBarThemeActivity> mActivityRule = new ActivityTestRule<>(
+ LightBarThemeActivity.class);
+
+ @Test
+ public void testThemeSetsFlags() {
+ final int flags = mActivityRule.getActivity().getWindow().getAttributes()
+ .systemUiVisibility;
+ Assert.assertTrue((flags & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0);
+ Assert.assertTrue((flags & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0);
+ }
+}
diff --git a/tests/tests/text/assets/ellipsis_test_font.ttf b/tests/tests/text/assets/ellipsis_test_font.ttf
new file mode 100644
index 0000000..ad0d79b
--- /dev/null
+++ b/tests/tests/text/assets/ellipsis_test_font.ttf
Binary files differ
diff --git a/tests/tests/text/assets/ellipsis_test_font.ttx b/tests/tests/text/assets/ellipsis_test_font.ttx
new file mode 100644
index 0000000..0c74b47
--- /dev/null
+++ b/tests/tests/text/assets/ellipsis_test_font.ttx
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ <GlyphID id="2" name="ellipsis"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x10000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="0"/>
+ <mtx name="a" width="1000" lsb="0"/>
+ <mtx name="ellipsis" width="1000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" /> <!-- LATIN SMALL LETTER A -->
+ <map code="0x2026" name="ellipsis" /> <!-- HORIZONTAL ELLIPSIS -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="ellipsis" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2017 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <GPOS>
+ <Version value="0x00010000"/>
+ <ScriptList>
+ <!-- ScriptCount=1 -->
+ <ScriptRecord index="0">
+ <ScriptTag value="DFLT"/>
+ <Script>
+ <DefaultLangSys>
+ <ReqFeatureIndex value="65535"/>
+ <!-- FeatureCount=1 -->
+ <FeatureIndex index="0" value="0"/>
+ </DefaultLangSys>
+ <!-- LangSysCount=0 -->
+ </Script>
+ </ScriptRecord>
+ </ScriptList>
+ <FeatureList>
+ <!-- FeatureCount=1 -->
+ <FeatureRecord index="0">
+ <FeatureTag value="kern"/>
+ <Feature>
+ <!-- LookupCount=1 -->
+ <LookupListIndex index="0" value="0"/>
+ </Feature>
+ </FeatureRecord>
+ </FeatureList>
+ <LookupList>
+ <!-- LookupCount=1 -->
+ <Lookup index="0">
+ <LookupType value="2"/>
+ <LookupFlag value="0"/>
+ <PairPos index="0" Format="1">
+ <Coverage Format="1">
+ <Glyph value="a"/>
+ <Glyph value="ellipsis"/>
+ </Coverage>
+ <ValueFormat1 value="4"/>
+ <ValueFormat2 value="0"/>
+ <PairSet index="0">
+ <PairValueRecord index="0">
+ <SecondGlyph value="ellipsis"/>
+ <Value1 XAdvance="500"/>
+ </PairValueRecord>
+ </PairSet>
+ <PairSet index="1">
+ <PairValueRecord index="0">
+ <SecondGlyph value="a"/>
+ <Value1 XAdvance="500"/>
+ </PairValueRecord>
+ </PairSet>
+ </PairPos>
+ </Lookup>
+ </LookupList>
+ </GPOS>
+</ttFont>
diff --git a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
index e78fb3e..f2a7b5a 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyInt;
@@ -36,6 +37,8 @@
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.BoringLayout;
@@ -345,6 +348,91 @@
anyInt(), anyInt(), anyFloat(), anyFloat(), any(Paint.class));
}
+ @Test
+ public void testEllipsize_End() {
+ // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think "aa…"
+ // would fit, but after measuring the new text, we find that it doesn't and we need to
+ // retry.
+ final float size = 100.0f;
+ final int allocatedWidth = (int) (3.4f * size);
+ final BoringLayout layout = new BoringLayout(
+ "aaaa",
+ getTextPaintForEllipsize(size),
+ allocatedWidth,
+ DEFAULT_ALIGN,
+ SPACING_MULT_NO_SCALE,
+ SPACING_ADD_NO_SCALE,
+ createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+ false /* includepad */,
+ TextUtils.TruncateAt.END,
+ allocatedWidth);
+ assertEquals("a\u2026\uFEFF\uFEFF", layout.getText().toString());
+ }
+
+ @Test
+ public void testEllipsize_Start() {
+ // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think "…aa"
+ // would fit, but after measuring the new text, we find that it doesn't and we need to
+ // retry.
+ final float size = 100.0f;
+ final int allocatedWidth = (int) (3.4f * size);
+ final BoringLayout layout = new BoringLayout(
+ "aaaa",
+ getTextPaintForEllipsize(size),
+ allocatedWidth,
+ DEFAULT_ALIGN,
+ SPACING_MULT_NO_SCALE,
+ SPACING_ADD_NO_SCALE,
+ createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+ false /* includepad */,
+ TextUtils.TruncateAt.START,
+ allocatedWidth);
+ assertEquals("\u2026\uFEFF\uFEFFa", layout.getText().toString());
+ }
+
+ @Test
+ public void testEllipsize_Middle() {
+ // When we try to ellipsize "aaaaaa" into a thinner 5.9 em space, we originally think
+ // "aa…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+ // to retry.
+ final float size = 100.0f;
+ final int allocatedWidth = (int) (5.9f * size);
+ final BoringLayout layout = new BoringLayout(
+ "aaaaaa",
+ getTextPaintForEllipsize(size),
+ allocatedWidth,
+ DEFAULT_ALIGN,
+ SPACING_MULT_NO_SCALE,
+ SPACING_ADD_NO_SCALE,
+ createMetrics(0, 0, 0, 0, allocatedWidth, 0),
+ false /* includepad */,
+ TextUtils.TruncateAt.MIDDLE,
+ allocatedWidth);
+ final String ellipsizedString = layout.getText().toString();
+ assertTrue("aa\u2026\uFEFF\uFEFFa".equals(ellipsizedString)
+ || "a\u2026\uFEFF\uFEFFaa".equals(ellipsizedString));
+ }
+
+ private TextPaint getTextPaintForEllipsize(float size) {
+ // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+ // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+ // ellipsis, half an em is added between them as kerning. This means that:
+ // "aaaa" is 4 ems wide,
+ // "aaa…" is 4.5 ems wide,
+ // "aa…" is 3.5 ems wide,
+ // "a…" is 2.5 ems wide,
+ // "aa…aa" is 6 ems wide,
+ // "aa…a" is 5 ems wide,
+ // "a…aa" is 5 ems wide,
+ // "a…a" is 4 ems wide,
+ // "…a" is 2.5 ems wide.
+ final TextPaint paint = new TextPaint();
+ paint.setTypeface(Typeface.createFromAsset(
+ InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+ paint.setTextSize(size);
+ return paint;
+ }
+
private static Metrics createMetrics(
final int top,
final int ascent,
diff --git a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
index 02139c5..d37f0ca 100644
--- a/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/DynamicLayoutTest.java
@@ -29,6 +29,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.text.DynamicLayout;
import android.text.Layout;
+import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
@@ -44,6 +45,7 @@
private static final float SPACING_MULT_NO_SCALE = 1.0f;
private static final float SPACING_ADD_NO_SCALE = 0.0f;
private static final int DEFAULT_OUTER_WIDTH = 150;
+ private static final int ELLIPSIZE_WIDTH = 8;
private static final CharSequence SINGLELINE_CHAR_SEQUENCE = "......";
private static final String[] TEXT = {"CharSequence\n", "Char\tSequence\n", "CharSequence"};
private static final CharSequence MULTLINE_CHAR_SEQUENCE = TEXT[0] + TEXT[1] + TEXT[2];
@@ -110,7 +112,7 @@
DEFAULT_ALIGN,
SPACING_MULT_NO_SCALE,
SPACING_ADD_NO_SCALE,
- true,
+ true /* include pad */,
TextUtils.TruncateAt.START,
DEFAULT_OUTER_WIDTH);
assertEquals(0, dynamicLayout.getEllipsisCount(LINE1));
@@ -118,6 +120,24 @@
assertEquals(DEFAULT_OUTER_WIDTH, dynamicLayout.getEllipsizedWidth());
}
+ // This could cause a crash in an older version of ellipsization code.
+ @Test
+ public void testEllipsisWithReflow() {
+ final String text = "Ham & Cheese.sandwich";
+ final int width = 1 << 20;
+ final int ellipsizedWidth = 2 * (int) mDefaultPaint.getTextSize();
+ final DynamicLayout dynamicLayout = new DynamicLayout(text,
+ text,
+ mDefaultPaint,
+ width,
+ DEFAULT_ALIGN,
+ SPACING_MULT_NO_SCALE,
+ SPACING_ADD_NO_SCALE,
+ true /* include pad */,
+ TextUtils.TruncateAt.END,
+ ellipsizedWidth);
+ }
+
/*
* Test whether include the padding to calculate the layout.
* 1. Include padding while calculate the layout.
@@ -194,6 +214,62 @@
assertEquals(TEXT[0].length() + TEXT[1].length(), mDynamicLayout.getLineStart(LINE2));
}
+ @Test
+ public void testLineSpacing() {
+ SpannableStringBuilder text = new SpannableStringBuilder("a\nb\nc");
+ final float spacingMultiplier = 2f;
+ final float spacingAdd = 4;
+ final int width = 1000;
+ final TextPaint textPaint = new TextPaint();
+ // create the DynamicLayout
+ final DynamicLayout dynamicLayout = new DynamicLayout(text,
+ textPaint,
+ width,
+ ALIGN_NORMAL,
+ spacingMultiplier,
+ spacingAdd,
+ false /*includepad*/);
+
+ // create a StaticLayout with same text, this will define the expectations
+ Layout expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+ spacingMultiplier);
+ assertLineSpecs(expected, dynamicLayout);
+
+ // add a new line to the end, DynamicLayout will re-calculate
+ text = text.append("\nd");
+ expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+ spacingMultiplier);
+ assertLineSpecs(expected, dynamicLayout);
+
+ // insert a next line and a char as the new second line
+ text = text.insert(TextUtils.indexOf(text, '\n') + 1, "a1\n");
+ expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+ spacingMultiplier);
+ assertLineSpecs(expected, dynamicLayout);
+ }
+
+ @Test
+ public void testLineSpacing_textEndingWithNextLine() {
+ final SpannableStringBuilder text = new SpannableStringBuilder("a\n");
+ final float spacingMultiplier = 2f;
+ final float spacingAdd = 4f;
+ final int width = 1000;
+ final TextPaint textPaint = new TextPaint();
+ // create the DynamicLayout
+ final DynamicLayout dynamicLayout = new DynamicLayout(text,
+ textPaint,
+ width,
+ ALIGN_NORMAL,
+ spacingMultiplier,
+ spacingAdd,
+ false /*includepad*/);
+
+ // create a StaticLayout with same text, this will define the expectations
+ final Layout expected = createStaticLayout(text.toString(), textPaint, width, spacingAdd,
+ spacingMultiplier);
+ assertLineSpecs(expected, dynamicLayout);
+ }
+
private Layout createStaticLayout(CharSequence text, TextPaint textPaint, int width,
float spacingAdd, float spacingMultiplier) {
return StaticLayout.Builder.obtain(text, 0,
@@ -253,4 +329,93 @@
spacingMultiplier);
assertLineSpecs(expected, dynamicLayout);
}
+
+ @Test
+ public void testBuilder_obtain() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ final DynamicLayout layout = builder.build();
+ // Check values passed to obtain().
+ assertEquals(MULTLINE_CHAR_SEQUENCE, layout.getText());
+ assertEquals(mDefaultPaint, layout.getPaint());
+ assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+ // Check default values.
+ assertEquals(Layout.Alignment.ALIGN_NORMAL, layout.getAlignment());
+ assertEquals(0.0f, layout.getSpacingAdd(), 0.0f);
+ assertEquals(1.0f, layout.getSpacingMultiplier(), 0.0f);
+ assertEquals(DEFAULT_OUTER_WIDTH, layout.getEllipsizedWidth());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testBuilder_obtainWithNullText() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(null, mDefaultPaint, 0);
+ final DynamicLayout layout = builder.build();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testBuilder_obtainWithNullPaint() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ null, 0);
+ final DynamicLayout layout = builder.build();
+ }
+
+ @Test
+ public void testBuilder_setDisplayTest() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setDisplayText(SINGLELINE_CHAR_SEQUENCE);
+ final DynamicLayout layout = builder.build();
+ assertEquals(SINGLELINE_CHAR_SEQUENCE, layout.getText());
+ }
+
+ @Test
+ public void testBuilder_setAlignment() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setAlignment(DEFAULT_ALIGN);
+ final DynamicLayout layout = builder.build();
+ assertEquals(DEFAULT_ALIGN, layout.getAlignment());
+ }
+
+ @Test
+ public void testBuilder_setLineSpacing() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setLineSpacing(1.0f, 2.0f);
+ final DynamicLayout layout = builder.build();
+ assertEquals(1.0f, layout.getSpacingAdd(), 0.0f);
+ assertEquals(2.0f, layout.getSpacingMultiplier(), 0.0f);
+ }
+
+ @Test
+ public void testBuilder_ellipsization() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setEllipsize(TextUtils.TruncateAt.END)
+ .setEllipsizedWidth(ELLIPSIZE_WIDTH);
+ final DynamicLayout layout = builder.build();
+ assertEquals(ELLIPSIZE_WIDTH, layout.getEllipsizedWidth());
+ assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth());
+ for (int i = 0; i < TEXT.length; i++) {
+ if (i == TEXT.length - 1) { // last line
+ assertTrue(layout.getEllipsisCount(i) > 0);
+ } else {
+ assertEquals(0, layout.getEllipsisCount(i));
+ }
+ }
+ }
+
+ @Test
+ public void testBuilder_otherSetters() {
+ // Setter methods that cannot be directly tested.
+ // setBreakStrategy, setHyphenationFrequency, setIncludePad, and setJustificationMode.
+ final DynamicLayout.Builder builder = DynamicLayout.Builder.obtain(MULTLINE_CHAR_SEQUENCE,
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL)
+ .setIncludePad(true)
+ .setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD);
+ final DynamicLayout layout = builder.build();
+ assertNotNull(layout);
+ }
}
diff --git a/tests/tests/text/src/android/text/cts/SelectionTest.java b/tests/tests/text/src/android/text/cts/SelectionTest.java
index f920bda..2aac83b 100644
--- a/tests/tests/text/src/android/text/cts/SelectionTest.java
+++ b/tests/tests/text/src/android/text/cts/SelectionTest.java
@@ -23,6 +23,7 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
@@ -275,6 +276,56 @@
}
@Test
+ public void testMoveUpAfterTyping() {
+ CharSequence text = "aaa\nmm";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 1, 1);
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(5, Selection.getSelectionStart(builder));
+ assertEquals(5, Selection.getSelectionEnd(builder));
+
+ builder.insert(5, "mm");
+ layout = new StaticLayout(builder, new TextPaint(), 200, Layout.Alignment.ALIGN_NORMAL,
+ 0, 0, false);
+ assertEquals(7, Selection.getSelectionStart(builder));
+ assertEquals(7, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testMoveUpKeepsOriginalMemoryPosition() {
+ CharSequence text = "aa\nm";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 1, 1);
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(4, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
public void testMoveDown() {
CharSequence text = "hello,world\nGoogle";
SpannableStringBuilder builder = new SpannableStringBuilder(text);
@@ -313,6 +364,340 @@
}
@Test
+ public void testMoveDownAfterTyping() {
+ CharSequence text = "mm\naaa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 4, 4);
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+
+ builder.insert(1, "mm");
+ layout = new StaticLayout(builder, new TextPaint(), 200, Layout.Alignment.ALIGN_NORMAL,
+ 0, 0, false);
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(8, Selection.getSelectionStart(builder));
+ assertEquals(8, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testMoveDownKeepsOriginalMemoryPosition() {
+ CharSequence text = "m\naa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 3, 3);
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
+ public void testMemoryPositionResetByHorizontalMovement() {
+ CharSequence text = "m\naa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 3, 3);
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveRight(builder, layout));
+ assertEquals(4, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(4, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveLeft(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 3, 3);
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
+ public void testMemoryPositionResetByRemoveSelection() {
+ CharSequence text = "m\naa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 3, 3);
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.removeSelection(builder);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
+ public void testMultilineLengthMoveDown() {
+ CharSequence text = "a\n\na";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 1);
+ // Move down to empty line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(2, Selection.getSelectionStart(builder));
+ assertEquals(2, Selection.getSelectionEnd(builder));
+
+ // Move down to third line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(4, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testMultilineLengthExtendDown() {
+ CharSequence text = "Google\n\nhello, world";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 1, 3);
+ assertTrue(Selection.extendDown(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(7, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.extendDown(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(15, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.extendDown(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(text.length(), Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testExtendDownKeepsOriginalMemoryPosition() {
+ CharSequence text = "m\naa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 3, 3);
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.extendDown(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
+ public void testMultilineLengthMoveUp() {
+ CharSequence text = "a\n\na";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 4);
+ // Move up to empty line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(2, Selection.getSelectionStart(builder));
+ assertEquals(2, Selection.getSelectionEnd(builder));
+
+ // Move up to first line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testMultilineLengthExtendUp() {
+ CharSequence text = "Google\n\nhello, world";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(0, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 9, 16);
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(9, Selection.getSelectionStart(builder));
+ assertEquals(7, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(9, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(9, Selection.getSelectionStart(builder));
+ assertEquals(0, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testExtendUpKeepsOriginalMemoryPosition() {
+ CharSequence text = "aa\nm";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(builder, new TextPaint(), 200,
+ Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+ assertEquals(0,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ Selection.setSelection(builder, 1, 1);
+ assertTrue(Selection.extendDown(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(4, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+
+ assertTrue(Selection.extendUp(builder, layout));
+ assertEquals(1, Selection.getSelectionStart(builder));
+ assertEquals(1, Selection.getSelectionEnd(builder));
+ assertEquals(1,
+ builder.getSpans(0, builder.length(), Selection.MemoryTextWatcher.class).length);
+ }
+
+ @Test
+ public void testMultilineLengthMoveDownAfterSelection() {
+ CharSequence text = "aaaaa\n\naaaaa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 3);
+ // Move down to empty line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(6, Selection.getSelectionStart(builder));
+ assertEquals(6, Selection.getSelectionEnd(builder));
+
+ // Move down to third line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(3, Selection.getSelectionStart(builder));
+ assertEquals(3, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 5);
+ // Move down to empty line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(6, Selection.getSelectionStart(builder));
+ assertEquals(6, Selection.getSelectionEnd(builder));
+
+ // Move down to third line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(5, Selection.getSelectionStart(builder));
+ assertEquals(5, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
+ public void testMultilineLengthMoveUpAfterSelection() {
+ CharSequence text = "aaaaa\n\naaaaa";
+ SpannableStringBuilder builder = new SpannableStringBuilder(text);
+ StaticLayout layout = new StaticLayout(text, new TextPaint(), 200, null, 0, 0, false);
+ assertEquals(-1, Selection.getSelectionStart(builder));
+ assertEquals(-1, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 10);
+ // Move up to empty line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(6, Selection.getSelectionStart(builder));
+ assertEquals(6, Selection.getSelectionEnd(builder));
+
+ // Move down to third line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(10, Selection.getSelectionStart(builder));
+ assertEquals(10, Selection.getSelectionEnd(builder));
+
+ Selection.setSelection(builder, 12);
+ // Move up to empty line
+ assertTrue(Selection.moveUp(builder, layout));
+ assertEquals(6, Selection.getSelectionStart(builder));
+ assertEquals(6, Selection.getSelectionEnd(builder));
+
+ // Move down to third line
+ assertTrue(Selection.moveDown(builder, layout));
+ assertEquals(12, Selection.getSelectionStart(builder));
+ assertEquals(12, Selection.getSelectionEnd(builder));
+ }
+
+ @Test
public void testExtendSelection() {
CharSequence text = "hello, world";
SpannableStringBuilder builder = new SpannableStringBuilder(text);
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 4f022a5..bc714b2 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -23,7 +23,9 @@
import static org.junit.Assert.fail;
import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.text.Editable;
import android.text.Layout;
@@ -59,6 +61,13 @@
private static final int LINE_COUNT = 6;
private static final int LARGER_THAN_LINE_COUNT = 50;
+ private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing "
+ + "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad "
+ + "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
+ + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
+ + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
+ + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+
/* the first line must have one tab. the others not. totally 6 lines
*/
private static final CharSequence LAYOUT_TEXT = "CharSe\tq\nChar"
@@ -203,8 +212,8 @@
// setBreakStrategy, setHyphenationFrequency, setIncludePad, and setIndents.
StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
- builder.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY);
- builder.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_FULL);
+ builder.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY);
+ builder.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
builder.setIncludePad(true);
builder.setIndents(null, null);
StaticLayout layout = builder.build();
@@ -213,6 +222,38 @@
}
@Test
+ public void testSetLineSpacing_whereLineEndsWithNextLine() {
+ final float spacingAdd = 10f;
+ final float spacingMult = 3f;
+
+ // two lines of text, with line spacing, first line will have the spacing, but last line
+ // wont have the spacing
+ final String tmpText = "a\nb";
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(tmpText, 0, tmpText.length(),
+ mDefaultPaint, DEFAULT_OUTER_WIDTH);
+ builder.setLineSpacing(spacingAdd, spacingMult).setIncludePad(false);
+ final StaticLayout comparisonLayout = builder.build();
+
+ assertEquals(2, comparisonLayout.getLineCount());
+ final int heightWithLineSpacing = comparisonLayout.getLineBottom(0)
+ - comparisonLayout.getLineTop(0);
+ final int heightWithoutLineSpacing = comparisonLayout.getLineBottom(1)
+ - comparisonLayout.getLineTop(1);
+ assertTrue(heightWithLineSpacing > heightWithoutLineSpacing);
+
+ final String text = "a\n";
+ // build the layout to be tested
+ builder = StaticLayout.Builder.obtain("a\n", 0, text.length(), mDefaultPaint,
+ DEFAULT_OUTER_WIDTH);
+ builder.setLineSpacing(spacingAdd, spacingMult).setIncludePad(false);
+ final StaticLayout layout = builder.build();
+
+ assertEquals(comparisonLayout.getLineCount(), layout.getLineCount());
+ assertEquals(heightWithLineSpacing, layout.getLineBottom(0) - layout.getLineTop(0));
+ assertEquals(heightWithoutLineSpacing, layout.getLineBottom(1) - layout.getLineTop(1));
+ }
+
+ @Test
public void testBuilder_setJustificationMode() {
StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0,
LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
@@ -222,6 +263,7 @@
// without causing any exceptions.
assertNotNull(layout);
}
+
/*
* Get the line number corresponding to the specified vertical position.
* If you ask for a position above 0, you get 0. above 0 means pixel above the fire line
@@ -1171,6 +1213,91 @@
assertTrue(layout.getEllipsisStart(0) != 0);
}
+ @Test
+ public void testEllipsize_retryEnd() {
+ final float size = 100.0f;
+
+ final int allocatedWidth = (int) (3.4f * size);
+ final String text = "aaaa";
+ final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+ getTextPaintForEllipsize(size), allocatedWidth)
+ .setEllipsize(TextUtils.TruncateAt.END)
+ .setEllipsizedWidth(allocatedWidth)
+ .setMaxLines(1)
+ .build();
+ assertEquals(1, layout.getEllipsisStart(0)); // After the first 'a'
+ assertEquals(3, layout.getEllipsisCount(0));
+ }
+
+ @Test
+ public void testEllipsize_retryEndRtl() {
+ final float size = 100.0f;
+
+ final int allocatedWidth = (int) (3.4f * size);
+ final String text = "\u202Eaaaa"; // U+202E is the RIGHT-TO-LEFT OVERRIDE.
+ final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+ getTextPaintForEllipsize(size), allocatedWidth)
+ .setEllipsize(TextUtils.TruncateAt.END)
+ .setEllipsizedWidth(allocatedWidth)
+ .setMaxLines(1)
+ .build();
+ assertEquals(2, layout.getEllipsisStart(0)); // After the first 'a'
+ assertEquals(3, layout.getEllipsisCount(0));
+ }
+
+ @Test
+ public void testEllipsize_retryStart() {
+ final float size = 100.0f;
+
+ final int allocatedWidth = (int) (3.4f * size);
+ final String text = "aaaa";
+ final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+ getTextPaintForEllipsize(size), allocatedWidth)
+ .setEllipsize(TextUtils.TruncateAt.START)
+ .setEllipsizedWidth(allocatedWidth)
+ .setMaxLines(1)
+ .build();
+ assertEquals(0, layout.getEllipsisStart(0));
+ assertEquals(3, layout.getEllipsisCount(0));
+ }
+
+ @Test
+ public void testEllipsize_retryMiddle() {
+ final float size = 100.0f;
+
+ final int allocatedWidth = (int) (5.9f * size);
+ final String text = "aaaaaa";
+ final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(),
+ getTextPaintForEllipsize(size), allocatedWidth)
+ .setEllipsize(TextUtils.TruncateAt.MIDDLE)
+ .setEllipsizedWidth(allocatedWidth)
+ .setMaxLines(1)
+ .build();
+ final int ellipsisStart = layout.getEllipsisStart(0);
+ assertTrue(ellipsisStart == 1 || ellipsisStart == 2);
+ assertEquals(3, layout.getEllipsisCount(0));
+ }
+
+ private TextPaint getTextPaintForEllipsize(float size) {
+ // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+ // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+ // ellipsis, half an em is added between them as kerning. This means that:
+ // "aaaa" is 4 ems wide,
+ // "aaa…" is 4.5 ems wide,
+ // "aa…" is 3.5 ems wide,
+ // "a…" is 2.5 ems wide,
+ // "aa…aa" is 6 ems wide,
+ // "aa…a" is 5 ems wide,
+ // "a…aa" is 5 ems wide,
+ // "a…a" is 4 ems wide,
+ // "…a" is 2.5 ems wide.
+ final TextPaint paint = new TextPaint();
+ paint.setTypeface(Typeface.createFromAsset(
+ InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+ paint.setTextSize(size);
+ return paint;
+ }
+
@Test(expected = IndexOutOfBoundsException.class)
public void testGetPrimary_shouldFail_whenOffsetIsOutOfBounds_withSpannable() {
final String text = "1\n2\n3";
@@ -1190,4 +1317,38 @@
.setEllipsize(TruncateAt.END).build();
layout.getPrimaryHorizontal(layout.getText().length());
}
+
+ // TODO: Re-enable once http://b/65207701 is fixed.
+ @Test
+ @Suppress
+ public void testGetLineWidth() {
+ final float wholeWidth = mDefaultPaint.measureText(LOREM_IPSUM);
+ final int lineWidth = (int) (wholeWidth / 10.0f); // Make 10 lines per paragraph.
+ final String multiParaTestString =
+ LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM;
+ final Layout layout = StaticLayout.Builder.obtain(multiParaTestString, 0,
+ multiParaTestString.length(), mDefaultPaint, lineWidth)
+ .build();
+ for (int i = 0; i < layout.getLineCount(); i++) {
+ assertTrue(layout.getLineWidth(i) <= lineWidth);
+ }
+ }
+
+ // TODO: Re-enable once http://b/65207701 is fixed.
+ @Test
+ @Suppress
+ public void testIndent() {
+ final float wholeWidth = mDefaultPaint.measureText(LOREM_IPSUM);
+ final int lineWidth = (int) (wholeWidth / 10.0f); // Make 10 lines per paragraph.
+ final int indentWidth = (int) (lineWidth * 0.3f); // Make 30% indent.
+ final String multiParaTestString =
+ LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM + "\n" + LOREM_IPSUM;
+ final Layout layout = StaticLayout.Builder.obtain(multiParaTestString, 0,
+ multiParaTestString.length(), mDefaultPaint, lineWidth)
+ .setIndents(new int[] { indentWidth }, null)
+ .build();
+ for (int i = 0; i < layout.getLineCount(); i++) {
+ assertTrue(layout.getLineWidth(i) <= lineWidth - indentWidth);
+ }
+ }
}
diff --git a/tests/tests/text/src/android/text/cts/TextUtilsTest.java b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
index d549cfa..2364dad 100644
--- a/tests/tests/text/src/android/text/cts/TextUtilsTest.java
+++ b/tests/tests/text/src/android/text/cts/TextUtilsTest.java
@@ -706,6 +706,83 @@
}
}
+ @Test
+ public void testEllipsize_retryEnd() {
+ // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+ // "aa…" would fit, but after measuring the new text, we find that it doesn't and we need
+ // to retry.
+ final float size = 100.0f;
+ final String text = "aaaa";
+
+ final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+ 3.4f * size,
+ TextUtils.TruncateAt.END, false /* preserveLength */, null /* callback */);
+ assertEquals("a\u2026", ellipsized.toString());
+ }
+
+ @Test
+ public void testEllipsize_retryEndRtl() {
+ // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+ // "aa…" would fit, but after measuring the new text, we find that it doesn't and we need
+ // to retry.
+ final float size = 100.0f;
+ final String text = "\u202Eaaaa"; // U+202E is the RIGHT-TO-LEFT OVERRIDE.
+
+ final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+ 3.4f * size,
+ TextUtils.TruncateAt.END, false /* preserveLength */, null /* callback */);
+ assertEquals("\u202Ea\u2026", ellipsized.toString());
+ }
+
+ @Test
+ public void testEllipsize_retryStart() {
+ // When we try to ellipsize "aaaa" into a thinner 3.4 em space, we originally think
+ // "…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+ // to retry.
+ final float size = 100.0f;
+ final String text = "aaaa";
+
+ final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+ 3.4f * size,
+ TextUtils.TruncateAt.START, false /* preserveLength */, null /* callback */);
+ assertEquals("\u2026a", ellipsized.toString());
+ }
+
+ @Test
+ public void testEllipsize_retryMiddle() {
+ // When we try to ellipsize "aaaaaa" into a thinner 5.9 em space, we originally think
+ // "aa…aa" would fit, but after measuring the new text, we find that it doesn't and we need
+ // to retry.
+ final float size = 100.0f;
+ final String text = "aaaaaa";
+
+ final CharSequence ellipsized = TextUtils.ellipsize(text, getTextPaintForEllipsize(size),
+ 5.9f * size,
+ TextUtils.TruncateAt.MIDDLE, false /* preserveLength */, null /* callback */);
+ final String ellipsizedString = ellipsized.toString();
+ assertTrue("aa\u2026a".equals(ellipsizedString) || "a\u2026aa".equals(ellipsizedString));
+ }
+
+ private TextPaint getTextPaintForEllipsize(float size) {
+ // The font used in this method has two glyphs defined for "a" and ellipsis. Both are one
+ // em wide. But the glyphs are kerned: whenever the "a" is followed or preceded by an
+ // ellipsis, half an em is added between them as kerning. This means that:
+ // "aaaa" is 4 ems wide,
+ // "aaa…" is 4.5 ems wide,
+ // "aa…" is 3.5 ems wide,
+ // "a…" is 2.5 ems wide,
+ // "aa…aa" is 6 ems wide,
+ // "aa…a" is 5 ems wide,
+ // "a…aa" is 5 ems wide,
+ // "a…a" is 4 ems wide,
+ // "…a" is 2.5 ems wide.
+ final TextPaint paint = new TextPaint();
+ paint.setTypeface(Typeface.createFromAsset(
+ InstrumentationRegistry.getTargetContext().getAssets(), "ellipsis_test_font.ttf"));
+ paint.setTextSize(size);
+ return paint;
+ }
+
/**
* Get a blank string which is filled up by '\uFEFF'.
*
@@ -1614,6 +1691,8 @@
spannableStringTokens.add(new SpannableString("span 2"));
spannableStringTokens.add(new SpannableString("span 3"));
assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
+
+ assertEquals("", TextUtils.join("|", new ArrayList<CharSequence>()));
}
@Test(expected=NullPointerException.class)
@@ -1636,6 +1715,8 @@
new SpannableString("span 2"),
new SpannableString("span 3") };
assertEquals("span 1;span 2;span 3", TextUtils.join(";", spannableStringTokens));
+
+ assertEquals("", TextUtils.join("|", new String[0]));
}
@Test(expected=NullPointerException.class)
diff --git a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
index 13c9aa2..50c97b2 100644
--- a/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateFormatTest.java
@@ -18,12 +18,15 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.UiAutomation;
import android.content.Context;
+import android.content.res.Configuration;
+import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.provider.Settings;
import android.support.annotation.NonNull;
@@ -312,6 +315,27 @@
}
}
+ @Test
+ public void test_ContextLocaleIsUsed() {
+ final Locale oldLocale = Locale.getDefault();
+
+ try {
+ Date date = new Date(YEAR_FROM_1900, MONTH, DAY);
+ Locale.setDefault(Locale.FRANCE);
+ final String javaResult = java.text.DateFormat.getDateInstance(
+ java.text.DateFormat.LONG).format(date);
+
+ final Configuration config = new Configuration();
+ config.setLocales(new LocaleList(Locale.JAPAN));
+ final Context context = mContext.createConfigurationContext(config);
+ final String androidResult = DateFormat.getLongDateFormat(context).format(date);
+
+ assertNotEquals(javaResult, androidResult);
+ } finally {
+ Locale.setDefault(oldLocale);
+ }
+ }
+
@NonNull
private String getTimeFormat() throws IOException {
return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
index 9c96519..4f26aea 100644
--- a/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerCtsActivity.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.os.Bundle;
-import android.os.SystemClock;
import android.text.cts.R;
import android.text.method.BaseKeyListener;
import android.text.method.DateKeyListener;
@@ -29,7 +28,6 @@
import android.text.method.QwertyKeyListener;
import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
-import android.util.Log;
/**
* This Activity is used for testing:
@@ -55,47 +53,9 @@
*/
public class KeyListenerCtsActivity extends Activity {
- private boolean mHasWindowFocus = false;
- private final Object mHasWindowFocusLock = new Object();
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.keylistener_layout);
}
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (!hasFocus) {
- Log.w("KeyListenerCtsActivity", "KeyListenerCtsActivity lost window focus");
- }
- synchronized(mHasWindowFocusLock) {
- mHasWindowFocus = hasFocus;
- mHasWindowFocusLock.notify();
- }
- }
-
- /**
- * Blocks the calling thread until the {@link KeyListenerCtsActivity} has window focus or the
- * specified duration (in milliseconds) has passed.
- */
- public boolean waitForWindowFocus(long durationMillis) {
- long elapsedMillis = SystemClock.elapsedRealtime();
- synchronized(mHasWindowFocusLock) {
- mHasWindowFocus = hasWindowFocus();
- while (!mHasWindowFocus && durationMillis > 0) {
- long newElapsedMillis = SystemClock.elapsedRealtime();
- durationMillis -= (newElapsedMillis - elapsedMillis);
- elapsedMillis = newElapsedMillis;
- if (durationMillis > 0) {
- try {
- mHasWindowFocusLock.wait(durationMillis);
- } catch (InterruptedException e) {
- }
- }
- }
- return mHasWindowFocus;
- }
- }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index ed0110a..ae8f57e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -47,6 +47,7 @@
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -294,9 +295,9 @@
.runWithVerifier(new RectVerifier(Color.WHITE, Color.GREEN, new Rect(40, 40, 70, 70)));
}
- // Note: This test will fail for Skia pipeline, but that is OK.
- // TODO: delete this test when Skia pipeline is default and modify next test
+ // STOPSHIP: delete this test when Skia pipeline ships as the default and modify next test
// testSaveLayerUnclippedWithColorFilterSW to run for both HW and SW
+ @Ignore
@Test
public void testSaveLayerUnclippedWithColorFilterHW() {
// verify that HW can draw nested unclipped layers with chained color filters
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
index 1717763..c2c8e87 100644
--- a/tests/tests/view/src/android/view/cts/TooltipTest.java
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -256,9 +256,6 @@
injectLongClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
- injectLongEnter(mTooltipView);
- assertFalse(hasTooltip(mTooltipView));
-
injectLongHoverMove(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
diff --git a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
index 774aadb..955cf7c 100644
--- a/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
+++ b/tests/tests/view/src/android/view/cts/VelocityTrackerTest.java
@@ -174,7 +174,7 @@
}
private void addMovement() {
- if (mTime >= mLastTime) {
+ if (mTime > mLastTime) {
MotionEvent ev = MotionEvent.obtain(0L, mTime, MotionEvent.ACTION_MOVE, mPx, mPy, 0);
mVelocityTracker.addMovement(ev);
ev.recycle();
@@ -201,9 +201,9 @@
if (errorVx > tolerance || errorVy > tolerance) {
fail(String.format("Velocity exceeds tolerance of %6.1f%%: "
+ "expected vx=%6.1f, vy=%6.1f. "
- + "actual vx=%6.1f (%6.1f%%), vy=%6.1f (%6.1f%%)",
+ + "actual vx=%6.1f (%6.1f%%), vy=%6.1f (%6.1f%%). %s",
tolerance * 100.0f, mVx, mVy,
- estimatedVx, errorVx * 100.0f, estimatedVy, errorVy * 100.0f));
+ estimatedVx, errorVx * 100.0f, estimatedVy, errorVy * 100.0f, message));
}
}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 831aa15..62537ba 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -149,7 +149,8 @@
PollingCheck.waitFor(mActivity::hasWindowFocus);
mResources = mActivity.getResources();
mMockParent = new MockViewParent(mActivity);
- assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
+ PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus);
+ assertTrue(mActivity.hasWindowFocus());
}
@Test
diff --git a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
index 9766fa2..9117925 100644
--- a/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/ViewTestCtsActivity.java
@@ -18,52 +18,13 @@
import android.app.Activity;
import android.os.Bundle;
-import android.os.SystemClock;
-import android.util.Log;
import android.view.cts.R;
public class ViewTestCtsActivity extends Activity {
- private boolean mHasWindowFocus = false;
- private final Object mHasWindowFocusLock = new Object();
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.view_layout);
}
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (!hasFocus) {
- Log.w("ViewTestCtsActivity", "ViewTestCtsActivity lost window focus");
- }
- synchronized(mHasWindowFocusLock) {
- mHasWindowFocus = hasFocus;
- mHasWindowFocusLock.notify();
- }
- }
-
- /**
- * Blocks the calling thread until the {@link ViewTestCtsActivity} has window focus or the
- * specified duration (in milliseconds) has passed.
- */
- public boolean waitForWindowFocus(long durationMillis) {
- long elapsedMillis = SystemClock.elapsedRealtime();
- synchronized(mHasWindowFocusLock) {
- mHasWindowFocus = hasWindowFocus();
- while (!mHasWindowFocus && durationMillis > 0) {
- long newElapsedMillis = SystemClock.elapsedRealtime();
- durationMillis -= (newElapsedMillis - elapsedMillis);
- elapsedMillis = newElapsedMillis;
- if (durationMillis > 0) {
- try {
- mHasWindowFocusLock.wait(durationMillis);
- } catch (InterruptedException e) {
- }
- }
- }
- return mHasWindowFocus;
- }
- }
}
diff --git a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
index 21fdd89..ae780fb 100644
--- a/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
+++ b/tests/tests/view/src/android/view/cts/View_FocusHandlingTest.java
@@ -227,6 +227,60 @@
@UiThreadTest
@Test
+ public void testEnabledHandling() {
+ Activity activity = mActivityRule.getActivity();
+
+ View v1 = activity.findViewById(R.id.view1);
+ View v2 = activity.findViewById(R.id.view2);
+ View v3 = activity.findViewById(R.id.view3);
+ View v4 = activity.findViewById(R.id.view4);
+
+ for (View v : new View[]{v1, v2, v3, v4}) v.setFocusable(true);
+
+ assertTrue(v1.requestFocus());
+
+ // disabled view should not be focusable
+ assertTrue(v1.hasFocus());
+ v1.setEnabled(false);
+ assertFalse(v1.hasFocus());
+ v1.requestFocus();
+ assertFalse(v1.hasFocus());
+ v1.setEnabled(true);
+ v1.requestFocus();
+ assertTrue(v1.hasFocus());
+
+ // an enabled view should not take focus if not visible OR not enabled
+ v1.setEnabled(false);
+ v1.setVisibility(View.INVISIBLE);
+ assertFalse(v1.hasFocus());
+ v1.setEnabled(true);
+ v1.requestFocus();
+ assertFalse(v1.hasFocus());
+ v1.setEnabled(false);
+ v1.setVisibility(View.VISIBLE);
+ v1.requestFocus();
+ assertFalse(v1.hasFocus());
+ v1.setEnabled(true);
+ v1.requestFocus();
+ assertTrue(v1.hasFocus());
+
+ // test hasFocusable
+ ViewGroup parent = (ViewGroup) v1.getParent();
+ assertTrue(parent.hasFocusable());
+ for (View v : new View[]{v1, v2, v3, v4}) v.setEnabled(false);
+ assertFalse(v1.isFocused());
+ assertFalse(v2.isFocused());
+ assertFalse(v3.isFocused());
+ assertFalse(v4.isFocused());
+ assertFalse(parent.hasFocusable());
+
+ // a view enabled while nothing has focus should get focus.
+ for (View v : new View[]{v1, v2, v3, v4}) v.setEnabled(true);
+ assertEquals(true, v1.isFocused());
+ }
+
+ @UiThreadTest
+ @Test
public void testFocusAuto() {
Activity activity = mActivityRule.getActivity();
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
index ecc3e4f..0fa239d 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -101,12 +101,26 @@
// Post a string message to main frame and make sure it is received.
public void testSimpleMessageToMainFrame() throws Throwable {
+ verifyPostMessageToOrigin(Uri.parse(BASE_URI));
+ }
+
+ // Post a string message to main frame passing a wildcard as target origin
+ public void testWildcardOriginMatchesAnything() throws Throwable {
+ verifyPostMessageToOrigin(Uri.parse("*"));
+ }
+
+ // Post a string message to main frame passing an empty string as target origin
+ public void testEmptyStringOriginMatchesAnything() throws Throwable {
+ verifyPostMessageToOrigin(Uri.parse(""));
+ }
+
+ private void verifyPostMessageToOrigin(Uri origin) throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
}
loadPage(TITLE_FROM_POST_MESSAGE);
WebMessage message = new WebMessage(WEBVIEW_MESSAGE);
- mOnUiThread.postWebMessage(message, Uri.parse(BASE_URI));
+ mOnUiThread.postWebMessage(message, origin);
waitForTitle(WEBVIEW_MESSAGE);
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index b4be068..a3eabaf 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -27,6 +27,7 @@
import android.graphics.Color;
import android.graphics.Picture;
import android.graphics.Rect;
+import android.graphics.pdf.PdfRenderer;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -2562,7 +2563,8 @@
// Called on UI thread
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- savePrintedPage(adapter, descriptor, result);
+ PageRange[] pageRanges = new PageRange[] {PageRange.ALL_PAGES};
+ savePrintedPage(adapter, descriptor, pageRanges, result);
}
});
try {
@@ -2580,6 +2582,57 @@
}
}
+ // Verify Print feature can create a PDF file with correct number of pages.
+ public void testPrintingPagesCount() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ String content = "<html><head></head><body>";
+ for (int i = 0; i < 500; ++i) {
+ content += "<br />abcdefghijk<br />";
+ }
+ content += "</body></html>";
+ mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
+ final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
+ printDocumentStart(adapter);
+ PrintAttributes attributes = new PrintAttributes.Builder()
+ .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+ .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
+ .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+ .build();
+ final WebViewCtsActivity activity = getActivity();
+ final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
+ final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
+ ParcelFileDescriptor.parseMode("w"));
+ final FutureTask<Boolean> result =
+ new FutureTask<Boolean>(new Callable<Boolean>() {
+ public Boolean call() {
+ return true;
+ }
+ });
+ printDocumentLayout(adapter, null, attributes,
+ new LayoutResultCallback() {
+ // Called on UI thread
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ PageRange[] pageRanges = new PageRange[] {
+ new PageRange(1, 1), new PageRange(4, 7)
+ };
+ savePrintedPage(adapter, descriptor, pageRanges, result);
+ }
+ });
+ try {
+ result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(file.length() > 0);
+ PdfRenderer renderer = new PdfRenderer(
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
+ assertEquals(5, renderer.getPageCount());
+ } finally {
+ descriptor.close();
+ file.delete();
+ }
+ }
+
public void testVisualStateCallbackCalled() throws Exception {
// Check that the visual state callback is called correctly.
if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2796,8 +2849,9 @@
}
private void savePrintedPage(final PrintDocumentAdapter adapter,
- final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
- adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
+ final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
+ final FutureTask<Boolean> result) {
+ adapter.onWrite(pageRanges, descriptor,
new CancellationSignal(),
new WriteResultCallback() {
@Override
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index d311d75..517c149 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -383,6 +383,44 @@
android:text="@string/sample_text"
android:justificationMode="inter_word" />
+ <TextView
+ android:id="@+id/textview_textappearance_attrs1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text"
+ style="@null"
+ android:textAppearance="@style/TextAppearance.Xml1" />
+
+ <TextView
+ android:id="@+id/textview_textappearance_attrs2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text"
+ style="@null"
+ android:textAppearance="@style/TextAppearance.Xml2" />
+
+ <TextView
+ android:id="@+id/textview_textappearance_attrs3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text"
+ android:textAppearance="@style/TextAppearance.Xml2"
+ style="@style/TextAppearance.Xml3" />
+
+ <TextView
+ android:id="@+id/textview_textappearance_attrs4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text"
+ style="@style/TextAppearance.Xml3" />
+
+ <TextView
+ android:id="@+id/textview_textappearance_attrs_allcaps_password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text"
+ style="@style/AllCapsPassword" />
+
</LinearLayout>
</ScrollView>
diff --git a/tests/tests/widget/res/menu/popup_menu.xml b/tests/tests/widget/res/menu/popup_menu.xml
index 29daad0..a2653b4 100644
--- a/tests/tests/widget/res/menu/popup_menu.xml
+++ b/tests/tests/widget/res/menu/popup_menu.xml
@@ -18,12 +18,14 @@
android:title="@string/popup_menu_highlight"
android:contentDescription="@string/popup_menu_highlight_description"
android:tooltipText="@string/popup_menu_highlight_tooltip" />
- <item android:id="@+id/action_edit"
- android:title="@string/popup_menu_edit"
- android:contentDescription="@string/popup_menu_edit_description"
- android:tooltipText="@string/popup_menu_edit_tooltip" />
- <item android:id="@+id/action_delete"
- android:title="@string/popup_menu_delete" />
+ <group android:id="@+id/group_test2">
+ <item android:id="@+id/action_edit"
+ android:title="@string/popup_menu_edit"
+ android:contentDescription="@string/popup_menu_edit_description"
+ android:tooltipText="@string/popup_menu_edit_tooltip" />
+ <item android:id="@+id/action_delete"
+ android:title="@string/popup_menu_delete" />
+ </group>
<item android:id="@+id/action_ignore"
android:title="@string/popup_menu_ignore" />
<item android:id="@+id/action_share"
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index a47f169..8d44c7a 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -109,6 +109,43 @@
<item name="android:textStyle">normal</item>
</style>
+ <style name="TextAppearance.Xml1">
+ <item name="android:textSize">22px</item>
+ <item name="android:typeface">sans</item>
+ <item name="android:textStyle">italic</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:letterSpacing">2.4</item>
+ <item name="android:fontFeatureSettings">smcp</item>
+ </style>
+
+ <style name="TextAppearance.Xml2">
+ <item name="android:fontFamily">monospace</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:shadowColor">@drawable/red</item>
+ <item name="android:shadowDx">10.3</item>
+ <item name="android:shadowDy">0.5</item>
+ <item name="android:shadowRadius">3.3</item>
+ <item name="android:elegantTextHeight">true</item>
+ </style>
+
+ <style name="TextAppearance.Xml3">
+ <item name="android:textSize">32px</item>
+ <item name="android:fontFamily">serif</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:letterSpacing">2.6</item>
+ <item name="android:shadowColor">@drawable/blue</item>
+ <item name="android:shadowDx">1.3</item>
+ <item name="android:shadowDy">10.5</item>
+ <item name="android:shadowRadius">5.3</item>
+ <item name="android:elegantTextHeight">false</item>
+ </style>
+
+ <style name="AllCapsPassword">
+ <item name="android:textAllCaps">true</item>
+ <item name="android:password">true</item>
+ </style>
+
<style name="TestEnum1">
<item name="testEnum">val1</item>
</style>
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 5ce73a8..0f89105 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -40,6 +40,7 @@
import android.view.SubMenu;
import android.view.View;
import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupMenu;
@@ -303,6 +304,36 @@
}
}
+ @Test
+ public void testGroupDividerEnabledAPI() throws Throwable {
+ testGroupDivider(false);
+ testGroupDivider(true);
+ }
+
+ private void testGroupDivider(boolean groupDividerEnabled) throws Throwable {
+ mBuilder = new Builder().withGroupDivider(groupDividerEnabled);
+ WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule, mBuilder::show, true);
+
+ Menu menu = mPopupMenu.getMenu();
+ ListView menuItemList = mPopupMenu.getMenuListView();
+
+ for (int i = 0; i < menuItemList.getCount(); i++) {
+ final int currGroupId = menu.getItem(i).getGroupId();
+ final int prevGroupId =
+ i - 1 >= 0 ? menu.getItem(i - 1).getGroupId() : currGroupId;
+ View itemView = menuItemList.getChildAt(i);
+ ImageView groupDivider = itemView.findViewById(com.android.internal.R.id.group_divider);
+
+ if (!groupDividerEnabled || currGroupId == prevGroupId) {
+ assertEquals(groupDivider.getVisibility(), View.GONE);
+ } else {
+ assertEquals(groupDivider.getVisibility(), View.VISIBLE);
+ }
+ }
+
+ teardown();
+ }
+
/**
* Inner helper class to configure an instance of {@link PopupMenu} for the specific test.
* The main reason for its existence is that once a popup menu is shown with the show() method,
@@ -328,6 +359,8 @@
private View mAnchor;
+ private boolean mGroupDividerEnabled = false;
+
public Builder withMenuItemClickListener() {
mHasMenuItemClickListener = true;
return this;
@@ -360,6 +393,11 @@
return this;
}
+ public Builder withGroupDivider(boolean groupDividerEnabled) {
+ mGroupDividerEnabled = groupDividerEnabled;
+ return this;
+ }
+
private void configure() {
mAnchor = mActivity.findViewById(R.id.anchor_middle_left);
if (!mUseCustomGravity && !mUseCustomPopupResource) {
@@ -390,6 +428,10 @@
mOnDismissListener = mock(PopupMenu.OnDismissListener.class);
mPopupMenu.setOnDismissListener(mOnDismissListener);
}
+
+ if (mGroupDividerEnabled) {
+ mPopupMenu.getMenu().setGroupDividerEnabled(true);
+ }
}
public void show() {
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 8b816fe..6e02824 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -4409,6 +4409,66 @@
assertEquals(null, mTextView.getTypeface());
}
+ @Test
+ public void testXmlTextAppearance() {
+ mTextView = findTextView(R.id.textview_textappearance_attrs1);
+ assertEquals(22f, mTextView.getTextSize(), 0.01f);
+ Typeface italicSans = Typeface.create(Typeface.SANS_SERIF, Typeface.ITALIC);
+ assertEquals(italicSans, mTextView.getTypeface());
+ assertEquals(Typeface.ITALIC, mTextView.getTypeface().getStyle());
+ assertTrue(mTextView.isAllCaps());
+ assertEquals(2.4f, mTextView.getLetterSpacing(), 0.01f);
+ assertEquals("smcp", mTextView.getFontFeatureSettings());
+
+ mTextView = findTextView(R.id.textview_textappearance_attrs2);
+ assertEquals(Typeface.MONOSPACE, mTextView.getTypeface());
+ assertEquals(mActivity.getResources().getColor(R.drawable.red),
+ mTextView.getShadowColor());
+ assertEquals(10.3f, mTextView.getShadowDx(), 0.01f);
+ assertEquals(0.5f, mTextView.getShadowDy(), 0.01f);
+ assertEquals(3.3f, mTextView.getShadowRadius(), 0.01f);
+ assertTrue(mTextView.isElegantTextHeight());
+
+ // This TextView has both a TextAppearance and a style, so the style should override.
+ mTextView = findTextView(R.id.textview_textappearance_attrs3);
+ assertEquals(32f, mTextView.getTextSize(), 0.01f);
+ Typeface boldSerif = Typeface.create(Typeface.SERIF, Typeface.BOLD);
+ assertEquals(boldSerif, mTextView.getTypeface());
+ assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
+ assertFalse(mTextView.isAllCaps());
+ assertEquals(2.6f, mTextView.getLetterSpacing(), 0.01f);
+ assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+ mTextView.getShadowColor());
+ assertEquals(1.3f, mTextView.getShadowDx(), 0.01f);
+ assertEquals(10.5f, mTextView.getShadowDy(), 0.01f);
+ assertEquals(5.3f, mTextView.getShadowRadius(), 0.01f);
+ assertFalse(mTextView.isElegantTextHeight());
+
+ // This TextView has no TextAppearance and has a style, so the style should be applied.
+ mTextView = findTextView(R.id.textview_textappearance_attrs4);
+ assertEquals(32f, mTextView.getTextSize(), 0.01f);
+ assertEquals(boldSerif, mTextView.getTypeface());
+ assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
+ assertFalse(mTextView.isAllCaps());
+ assertEquals(2.6f, mTextView.getLetterSpacing(), 0.01f);
+ assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+ mTextView.getShadowColor());
+ assertEquals(1.3f, mTextView.getShadowDx(), 0.01f);
+ assertEquals(10.5f, mTextView.getShadowDy(), 0.01f);
+ assertEquals(5.3f, mTextView.getShadowRadius(), 0.01f);
+ assertFalse(mTextView.isElegantTextHeight());
+
+ // Note: text, link and hint colors can't be tested due to the default style overriding
+ // values b/63923542
+ }
+
+ @Test
+ public void testAttributeReading_allCapsAndPassword() {
+ // This TextView has all caps & password, therefore all caps should be ignored.
+ mTextView = findTextView(R.id.textview_textappearance_attrs_allcaps_password);
+ assertFalse(mTextView.isAllCaps());
+ }
+
@UiThreadTest
@Test
public void testAccessCompoundDrawableTint() {
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
new file mode 100644
index 0000000..820f1bb
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ compatibility-device-util \
+ android-support-test \
+ legacy-android-test
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PREBUILT_JNI_LIBS_arm := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_arm64 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_mips := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_mips64 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_x86 := wrap.sh
+LOCAL_PREBUILT_JNI_LIBS_x86_64 := wrap.sh
+
+LOCAL_PACKAGE_NAME := CtsWrapWrapDebugMallocDebugTestCases
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
+
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml
new file mode 100644
index 0000000..a359f17
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.wrap.wrap_debug_malloc_debug.cts">
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ <meta-data android:name="android.wrap.cts.expext_env" android:value="true" />
+ <activity android:name="android.wrap.WrapActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <!-- self-instrumenting test package. -->
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:label="CTS tests for wrap.sh"
+ android:targetPackage="android.wrap.wrap_debug_malloc_debug.cts" >
+ </instrumentation>
+</manifest>
+
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml
new file mode 100644
index 0000000..ef5b71e
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Debug Wrap (Malloc Debug) test cases">
+ <option name="config-descriptor:metadata" key="component" value="art" />
+ <option name="not-shardable" value="true" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsWrapWrapDebugMallocDebugTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.wrap.wrap_debug_malloc_debug.cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh b/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh
new file mode 100755
index 0000000..f00a554
--- /dev/null
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/wrap.sh
@@ -0,0 +1,15 @@
+#!/system/bin/sh
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LIBC_DEBUG_MALLOC_OPTIONS=backtrace=1 WRAP_PROPERTY=test $@
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 5fed5b4..1008b67 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -121,6 +121,12 @@
<!-- b/36686383 -->
<option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
+ <!-- b/33090965 -->
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
+
<!-- b/37482372 -->
<option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowHistoryPreservePortraitTest" />
<option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInOutPortraitTest" />
@@ -165,6 +171,9 @@
<option name="compatibility:exclude-filter" value="x86_64 CtsMediaBitstreamsTestCases" />
<option name="compatibility:exclude-filter" value="mips64 CtsMediaBitstreamsTestCases" />
+ <!-- b/38280830 -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.VideoDecoderPerfTest#testVp8Goog0Perf1280x0720" />
+
<!-- b/38420898 -->
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyAccelMultiChannel" />
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRateIndependencyGyroMultiChannel" />
@@ -189,7 +198,4 @@
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testRegisterMultipleChannels" />
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testReconfigure" />
- <!-- b/63566721 -->
- <option name="compatibility:exclude-filter" value="CtsWrapWrapDebugTestCases android.wrap.cts.WrapTest" />
-
</configuration>
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 672ebe9..74118bd 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -25,7 +25,6 @@
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := junit
--include cts/error_prone_rules_tests.mk
include $(BUILD_JAVA_LIBRARY)
cts-tf-dalvik-lib.jack := $(full_classes_jack)