Squashed mnc-dev changes:
This contains all of the changes from b54aa51 to
791e51a on mnc-dev, except the changes
to tests/tests/security.
Bug: 24846656
Change-Id: I01f53a1a238ac49f86928e0e22796dc73e0e34af
diff --git a/CtsBuild.mk b/CtsBuild.mk
index c745885..ba158ce 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -40,6 +40,10 @@
$(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
endef
+define cts-get-deqp-api-test-xmls
+ $(foreach file,$(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(1).*xml', .),$(CTS_TESTCASES_OUT)/$(file))
+endef
+
define cts-get-deqp-test-xmls
- $(foreach api,$(1),$(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(api).xml)
+ $(foreach api,$(1),$(call cts-get-deqp-api-test-xmls,$(api)))
endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index cf7da2f..975ac47 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -100,6 +100,7 @@
CtsManagedProfileApp \
CtsMonkeyApp \
CtsMonkeyApp2 \
+ CtsPackageInstallerApp \
CtsPermissionApp \
CtsSimpleApp \
CtsSimplePreMApp \
@@ -193,6 +194,7 @@
CtsSecurityTestCases \
CtsSignatureTestCases \
CtsSpeechTestCases \
+ CtsSystemUiTestCases \
CtsTelecomTestCases \
CtsTelecomTestCases2 \
CtsTelephonyTestCases \
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 756f959..835a4a4 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -448,8 +448,8 @@
The out_surfaces field can specify the width(s), height(s), and
format(s) of the captured image. The formats may be "yuv", "jpeg",
- "dng", "raw", "raw10", or "raw12". The default is a YUV420 frame ("yuv")
- corresponding to a full sensor frame.
+ "dng", "raw", "raw10", "raw12", or "rawStats". The default is a YUV420
+ frame ("yuv") corresponding to a full sensor frame.
Note that one or more surfaces can be specified, allowing a capture to
request images back in multiple formats (e.g.) raw+yuv, raw+jpeg,
@@ -536,6 +536,25 @@
yuv_caps = do_capture( [req1,req2], yuv_fmt )
yuv_caps, raw_caps = do_capture( [req1,req2], [yuv_fmt,raw_fmt] )
+ The "rawStats" format processes the raw image and returns a new image
+ of statistics from the raw image. The format takes additional keys,
+ "gridWidth" and "gridHeight" which are size of grid cells in a 2D grid
+ of the raw image. For each grid cell, the mean and variance of each raw
+ channel is computed, and the do_capture call returns two 4-element float
+ images of dimensions (rawWidth / gridWidth, rawHeight / gridHeight),
+ concatenated back-to-back, where the first iamge contains the 4-channel
+ means and the second contains the 4-channel variances.
+
+ For the rawStats format, if the gridWidth is not provided then the raw
+ image width is used as the default, and similarly for gridHeight. With
+ this, the following is an example of a output description that computes
+ the mean and variance across each image row:
+
+ {
+ "gridHeight": 1,
+ "format": "rawStats"
+ }
+
Args:
cap_request: The Python dict/list specifying the capture(s), which
will be converted to JSON and sent to the device.
@@ -550,7 +569,8 @@
* data: the image data as a numpy array of bytes.
* width: the width of the captured image.
* height: the height of the captured image.
- * format: image the format, in ["yuv","jpeg","raw","raw10","dng"].
+ * format: image the format, in [
+ "yuv","jpeg","raw","raw10","raw12","rawStats","dng"].
* metadata: the capture result object (Python dictionary).
"""
cmd = {}
@@ -577,9 +597,13 @@
nsurf = 1 if out_surfaces is None else len(cmd["outputSurfaces"])
if len(formats) > len(set(formats)):
raise its.error.Error('Duplicate format requested')
- if "dng" in formats and "raw" in formats or \
- "dng" in formats and "raw10" in formats or \
- "raw" in formats and "raw10" in formats:
+ raw_formats = 0;
+ raw_formats += 1 if "dng" in formats else 0
+ raw_formats += 1 if "raw" in formats else 0
+ raw_formats += 1 if "raw10" in formats else 0
+ raw_formats += 1 if "raw12" in formats else 0
+ raw_formats += 1 if "rawStats" in formats else 0
+ if raw_formats > 1:
raise its.error.Error('Different raw formats not supported')
# Detect long exposure time and set timeout accordingly
@@ -603,14 +627,16 @@
# the burst, however individual images of different formats can come
# out in any order for that capture.
nbufs = 0
- bufs = {"yuv":[], "raw":[], "raw10":[], "dng":[], "jpeg":[]}
+ bufs = {"yuv":[], "raw":[], "raw10":[], "raw12":[],
+ "rawStats":[], "dng":[], "jpeg":[]}
mds = []
widths = None
heights = None
while nbufs < ncap*nsurf or len(mds) < ncap:
jsonObj,buf = self.__read_response_from_socket()
if jsonObj['tag'] in ['jpegImage', 'yuvImage', 'rawImage', \
- 'raw10Image', 'dngImage'] and buf is not None:
+ 'raw10Image', 'raw12Image', 'rawStatsImage', 'dngImage'] \
+ and buf is not None:
fmt = jsonObj['tag'][:-5]
bufs[fmt].append(buf)
nbufs += 1
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index ea01a3e..a5ac60b 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -81,6 +81,25 @@
else:
raise its.error.Error('Invalid format %s' % (cap["format"]))
+def unpack_rawstats_capture(cap):
+ """Unpack a rawStats capture to the mean and variance images.
+
+ Args:
+ cap: A capture object as returned by its.device.do_capture.
+
+ Returns:
+ Tuple (mean_image var_image) of float-4 images, with non-normalized
+ pixel values computed from the RAW16 images on the device
+ """
+ assert(cap["format"] == "rawStats")
+ w = cap["width"]
+ h = cap["height"]
+ img = numpy.ndarray(shape=(2*h*w*4,), dtype='<f', buffer=cap["data"])
+ analysis_image = img.reshape(2,h,w,4)
+ mean_image = analysis_image[0,:,:,:].reshape(h,w,4)
+ var_image = analysis_image[1,:,:,:].reshape(h,w,4)
+ return mean_image, var_image
+
def unpack_raw10_capture(cap, props):
"""Unpack a raw-10 capture to a raw-16 capture.
@@ -604,6 +623,21 @@
variances.append(numpy.var(img[:,:,i], dtype=numpy.float64))
return variances
+def compute_image_snrs(img):
+ """Calculate the SNR (db) of each color channel in the image.
+
+ Args:
+ img: Numpy float image array, with pixel values in [0,1].
+
+ Returns:
+ A list of SNR value, one per color channel in the image.
+ """
+ means = compute_image_means(img)
+ variances = compute_image_variances(img)
+ std_devs = [math.sqrt(v) for v in variances]
+ snr = [20 * math.log10(m/s) for m,s in zip(means, std_devs)]
+ return snr
+
def write_image(img, fname, apply_gamma=False):
"""Save a float-3 numpy array image to a file.
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index 82346ec..ac384fb 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -152,24 +152,37 @@
return req
-def get_available_output_sizes(fmt, props):
+def get_available_output_sizes(fmt, props, max_size=None, match_ar_size=None):
"""Return a sorted list of available output sizes for a given format.
Args:
fmt: the output format, as a string in
["jpg", "yuv", "raw", "raw10", "raw12"].
props: the object returned from its.device.get_camera_properties().
+ max_size: (Optional) A (w,h) tuple.
+ Sizes larger than max_size (either w or h) will be discarded.
+ match_ar_size: (Optional) A (w,h) tuple.
+ Sizes not matching the aspect ratio of match_ar_size will be
+ discarded.
Returns:
A sorted list of (w,h) tuples (sorted large-to-small).
"""
- fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26, "yuv":0x23,
+ AR_TOLERANCE = 0.03
+ fmt_codes = {"raw":0x20, "raw10":0x25, "raw12":0x26,"yuv":0x23,
"jpg":0x100, "jpeg":0x100}
configs = props['android.scaler.streamConfigurationMap']\
['availableStreamConfigurations']
fmt_configs = [cfg for cfg in configs if cfg['format'] == fmt_codes[fmt]]
out_configs = [cfg for cfg in fmt_configs if cfg['input'] == False]
out_sizes = [(cfg['width'],cfg['height']) for cfg in out_configs]
+ if max_size:
+ out_sizes = [s for s in out_sizes if
+ s[0] <= max_size[0] and s[1] <= max_size[1]]
+ if match_ar_size:
+ ar = match_ar_size[0] / float(match_ar_size[1])
+ out_sizes = [s for s in out_sizes if
+ abs(ar - s[0] / float(s[1])) <= AR_TOLERANCE]
out_sizes.sort(reverse=True)
return out_sizes
diff --git a/apps/CameraITS/tests/inprog/test_rawstats.py b/apps/CameraITS/tests/inprog/test_rawstats.py
new file mode 100644
index 0000000..8083f0b
--- /dev/null
+++ b/apps/CameraITS/tests/inprog/test_rawstats.py
@@ -0,0 +1,48 @@
+# Copyright 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.
+
+import its.image
+import its.caps
+import its.device
+import its.objects
+import its.target
+import os.path
+import math
+
+def main():
+ """Test capturing some rawstats data.
+ """
+ NAME = os.path.basename(__file__).split(".")[0]
+
+ with its.device.ItsSession() as cam:
+
+ cam.do_3a(do_af=False);
+ req = its.objects.auto_capture_request()
+
+ for (gw,gh) in [(16,16)]:#,(4080,1)]:
+ cap = cam.do_capture(req,
+ {"format":"rawStats","gridWidth":gw,"gridHeight":gh})
+ mean_image, var_image = its.image.unpack_rawstats_capture(cap)
+
+ if gw > 1 and gh > 1:
+ h,w,_ = mean_image.shape
+ for ch in range(4):
+ m = mean_image[:,:,ch].reshape(h,w,1)/1023.0
+ v = var_image[:,:,ch].reshape(h,w,1)
+ its.image.write_image(m, "%s_mean_ch%d.jpg" % (NAME,ch), True)
+ its.image.write_image(v, "%s_var_ch%d.jpg" % (NAME,ch), True)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index 26c398d..89bc724 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -35,8 +35,10 @@
THRESHOLD_MAX_OUTLIER_DIFF = 0.1
THRESHOLD_MIN_LEVEL = 0.1
THRESHOLD_MAX_LEVEL = 0.9
- THRESHOLD_MAX_LEVEL_DIFF = 0.025
+ THRESHOLD_MAX_LEVEL_DIFF = 0.03
THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE = 0.05
+ THRESHOLD_ROUND_DOWN_GAIN = 0.1
+ THRESHOLD_ROUND_DOWN_EXP = 0.05
mults = []
r_means = []
@@ -50,21 +52,33 @@
its.caps.per_frame_control(props))
e,s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
+ s_e_product = s*e
expt_range = props['android.sensor.info.exposureTimeRange']
sens_range = props['android.sensor.info.sensitivityRange']
- m = 1
+ m = 1.0
while s*m < sens_range[1] and e/m > expt_range[0]:
mults.append(m)
- req = its.objects.manual_capture_request(s*m, e/m)
+ s_test = round(s*m)
+ e_test = s_e_product / s_test
+ print "Testsing s:", s_test, "e:", e_test
+ req = its.objects.manual_capture_request(s_test, e_test)
cap = cam.do_capture(req)
+ s_res = cap["metadata"]["android.sensor.sensitivity"]
+ e_res = cap["metadata"]["android.sensor.exposureTime"]
+ assert(0 <= s_test - s_res < s_test * THRESHOLD_ROUND_DOWN_GAIN)
+ assert(0 <= e_test - e_res < e_test * THRESHOLD_ROUND_DOWN_EXP)
+ s_e_product_res = s_res * e_res
+ request_result_ratio = s_e_product / s_e_product_res
+ print "Capture result s:", s_test, "e:", e_test
img = its.image.convert_capture_to_rgb_image(cap)
its.image.write_image(img, "%s_mult=%3.2f.jpg" % (NAME, m))
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
rgb_means = its.image.compute_image_means(tile)
- r_means.append(rgb_means[0])
- g_means.append(rgb_means[1])
- b_means.append(rgb_means[2])
+ # Adjust for the difference between request and result
+ r_means.append(rgb_means[0] * request_result_ratio)
+ g_means.append(rgb_means[1] * request_result_ratio)
+ b_means.append(rgb_means[2] * request_result_ratio)
# Test 3 steps per 2x gain
m = m * pow(2, 1.0 / 3)
@@ -73,9 +87,9 @@
threshold_max_level_diff = THRESHOLD_MAX_LEVEL_DIFF_WIDE_RANGE
# Draw a plot.
- pylab.plot(mults, r_means, 'r')
- pylab.plot(mults, g_means, 'g')
- pylab.plot(mults, b_means, 'b')
+ pylab.plot(mults, r_means, 'r.-')
+ pylab.plot(mults, g_means, 'g.-')
+ pylab.plot(mults, b_means, 'b.-')
pylab.ylim([0,1])
matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME))
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index 35cfc07..1072684 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -35,12 +35,13 @@
"""
NAME = os.path.basename(__file__).split(".")[0]
- RELATIVE_ERROR_TOLERANCE = 0.1
- # List of variances for R,G,B.
- variances = [[],[],[]]
+ NUM_SAMPLES_PER_MODE = 4
+ SNR_TOLERANCE = 3 # unit in db
+ # List of SNRs for R,G,B.
+ snrs = [[], [], []]
- # Reference (baseline) variance for each of R,G,B.
- ref_variance = []
+ # Reference (baseline) SNR for each of R,G,B.
+ ref_snr = []
nr_modes_reported = []
@@ -60,8 +61,8 @@
rgb_image,
"%s_low_gain.jpg" % (NAME))
rgb_tile = its.image.get_image_patch(rgb_image, 0.45, 0.45, 0.1, 0.1)
- ref_variance = its.image.compute_image_variances(rgb_tile)
- print "Ref variances:", ref_variance
+ ref_snr = its.image.compute_image_snrs(rgb_tile)
+ print "Ref SNRs:", ref_snr
e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
# NR modes 0, 1, 2, 3, 4 with high gain
@@ -70,58 +71,74 @@
if not its.caps.noise_reduction_mode(props, mode):
nr_modes_reported.append(mode)
for channel in range(3):
- variances[channel].append(0)
+ snrs[channel].append(0)
continue;
- req = its.objects.manual_capture_request(s, e)
- req["android.noiseReduction.mode"] = mode
- cap = cam.do_capture(req)
- rgb_image = its.image.convert_capture_to_rgb_image(cap)
- nr_modes_reported.append(
- cap["metadata"]["android.noiseReduction.mode"])
- its.image.write_image(
- rgb_image,
- "%s_high_gain_nr=%d.jpg" % (NAME, mode))
- rgb_tile = its.image.get_image_patch(
- rgb_image, 0.45, 0.45, 0.1, 0.1)
- rgb_vars = its.image.compute_image_variances(rgb_tile)
+ rgb_snr_list = []
+ # Capture several images to account for per frame noise variations
+ for n in range(NUM_SAMPLES_PER_MODE):
+ req = its.objects.manual_capture_request(s, e)
+ req["android.noiseReduction.mode"] = mode
+ cap = cam.do_capture(req)
+ rgb_image = its.image.convert_capture_to_rgb_image(cap)
+ if n == 0:
+ nr_modes_reported.append(
+ cap["metadata"]["android.noiseReduction.mode"])
+ its.image.write_image(
+ rgb_image,
+ "%s_high_gain_nr=%d.jpg" % (NAME, mode))
+ rgb_tile = its.image.get_image_patch(
+ rgb_image, 0.45, 0.45, 0.1, 0.1)
+ rgb_snrs = its.image.compute_image_snrs(rgb_tile)
+ rgb_snr_list.append(rgb_snrs)
+
+ r_snrs = [rgb[0] for rgb in rgb_snr_list]
+ g_snrs = [rgb[1] for rgb in rgb_snr_list]
+ b_snrs = [rgb[2] for rgb in rgb_snr_list]
+ rgb_snrs = [numpy.mean(r_snrs), numpy.mean(g_snrs), numpy.mean(b_snrs)]
+ print "NR mode", mode, "SNRs:"
+ print " R SNR:", rgb_snrs[0],\
+ "Min:", min(r_snrs), "Max:", max(r_snrs)
+ print " G SNR:", rgb_snrs[1],\
+ "Min:", min(g_snrs), "Max:", max(g_snrs)
+ print " B SNR:", rgb_snrs[2],\
+ "Min:", min(b_snrs), "Max:", max(b_snrs)
+
for chan in range(3):
- variance = rgb_vars[chan]
- variances[chan].append(variance / ref_variance[chan])
- print "Variances with NR mode [0,1,2]:", variances
+ snrs[chan].append(rgb_snrs[chan])
# Draw a plot.
for j in range(3):
- pylab.plot(range(5), variances[j], "rgb"[j])
- matplotlib.pyplot.savefig("%s_plot_variances.png" % (NAME))
+ pylab.plot(range(5), snrs[j], "rgb"[j])
+ matplotlib.pyplot.savefig("%s_plot_SNRs.png" % (NAME))
assert(nr_modes_reported == [0,1,2,3,4])
for j in range(3):
- # Smaller variance is better
+ # Larger SNR is better
# Verify OFF(0) is not better than FAST(1)
- assert(variances[j][0] >
- variances[j][1] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][1] + SNR_TOLERANCE)
# Verify FAST(1) is not better than HQ(2)
- assert(variances[j][1] >
- variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][1] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify HQ(2) is better than OFF(0)
- assert(variances[j][0] > variances[j][2])
+ assert(snrs[j][0] < snrs[j][2])
if its.caps.noise_reduction_mode(props, 3):
# Verify OFF(0) is not better than MINIMAL(3)
- assert(variances[j][0] >
- variances[j][3] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][3] + SNR_TOLERANCE)
# Verify MINIMAL(3) is not better than HQ(2)
- assert(variances[j][3] >
- variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][3] <
+ snrs[j][2] + SNR_TOLERANCE)
if its.caps.noise_reduction_mode(props, 4):
# Verify ZSL(4) is close to MINIMAL(3)
- assert(numpy.isclose(variances[j][4], variances[j][3],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][3],
+ atol=SNR_TOLERANCE))
elif its.caps.noise_reduction_mode(props, 4):
# Verify ZSL(4) is close to OFF(0)
- assert(numpy.isclose(variances[j][4], variances[j][0],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][0],
+ atol=SNR_TOLERANCE))
if __name__ == '__main__':
main()
diff --git a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
index 6c2b5c1..e176312 100644
--- a/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_burst_sensitivity.py
@@ -44,6 +44,8 @@
# Expose for the scene with min sensitivity
sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+ # Digital gains might not be visible on RAW data
+ sens_max = props['android.sensor.maxAnalogSensitivity']
sens_step = (sens_max - sens_min) / NUM_STEPS
s_ae,e_ae,_,_,_ = cam.do_3a(get_results=True)
s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
index 14c5eb0..cc0ce14 100644
--- a/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
+++ b/apps/CameraITS/tests/scene1/test_raw_sensitivity.py
@@ -42,6 +42,8 @@
# Expose for the scene with min sensitivity
sens_min, sens_max = props['android.sensor.info.sensitivityRange']
+ # Digital gains might not be visible on RAW data
+ sens_max = props['android.sensor.maxAnalogSensitivity']
sens_step = (sens_max - sens_min) / NUM_STEPS
s_ae,e_ae,_,_,_ = cam.do_3a(get_results=True)
s_e_prod = s_ae * e_ae
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index 757dfeb..f0a6fbe 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -38,7 +38,8 @@
NAME = os.path.basename(__file__).split(".")[0]
- RELATIVE_ERROR_TOLERANCE = 0.1
+ NUM_SAMPLES_PER_MODE = 4
+ SNR_TOLERANCE = 3 # unit in db
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
@@ -60,7 +61,7 @@
for reprocess_format in reprocess_formats:
# List of variances for R, G, B.
- variances = []
+ snrs = [[], [], []]
nr_modes_reported = []
# NR mode 0 with low gain
@@ -77,71 +78,90 @@
img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
its.image.write_image(img, "%s_low_gain_fmt=jpg.jpg" % (NAME))
tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
- ref_variance = its.image.compute_image_variances(tile)
- print "Ref variances:", ref_variance
+ ref_snr = its.image.compute_image_snrs(tile)
+ print "Ref SNRs:", ref_snr
+ e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
for nr_mode in range(5):
# Skip unavailable modes
if not its.caps.noise_reduction_mode(props, nr_mode):
nr_modes_reported.append(nr_mode)
- variances.append(0)
+ for channel in range(3):
+ snrs[channel].append(0)
continue
- # NR modes with high gain
- e, s = its.target.get_target_exposure_combos(cam) \
- ["maxSensitivity"]
- req = its.objects.manual_capture_request(s, e)
- req["android.noiseReduction.mode"] = nr_mode
- cap = cam.do_capture(req, out_surface, reprocess_format)
- nr_modes_reported.append(
- cap["metadata"]["android.noiseReduction.mode"])
+ rgb_snr_list = []
+ # Capture several images to account for per frame noise
+ # variations
+ for n in range(NUM_SAMPLES_PER_MODE):
+ req = its.objects.manual_capture_request(s, e)
+ req["android.noiseReduction.mode"] = nr_mode
+ cap = cam.do_capture(req, out_surface, reprocess_format)
- img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
- its.image.write_image(
- img, "%s_high_gain_nr=%d_fmt=jpg.jpg" % (NAME, nr_mode))
- tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
- # Get the variances for R, G, and B channels
- variance = its.image.compute_image_variances(tile)
- variances.append(
- [variance[chan] / ref_variance[chan] for chan in range(3)])
- print "Variances with NR mode [0,1,2,3,4]:", variances
+ img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+ if n == 0:
+ its.image.write_image(
+ img,
+ "%s_high_gain_nr=%d_fmt=jpg.jpg"
+ %(NAME, nr_mode))
+ nr_modes_reported.append(
+ cap["metadata"]["android.noiseReduction.mode"])
+
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ # Get the variances for R, G, and B channels
+ rgb_snrs = its.image.compute_image_snrs(tile)
+ rgb_snr_list.append(rgb_snrs)
+
+ r_snrs = [rgb[0] for rgb in rgb_snr_list]
+ g_snrs = [rgb[1] for rgb in rgb_snr_list]
+ b_snrs = [rgb[2] for rgb in rgb_snr_list]
+ rgb_snrs = [numpy.mean(r_snrs),
+ numpy.mean(g_snrs),
+ numpy.mean(b_snrs)]
+ print "NR mode", nr_mode, "SNRs:"
+ print " R SNR:", rgb_snrs[0],\
+ "Min:", min(r_snrs), "Max:", max(r_snrs)
+ print " G SNR:", rgb_snrs[1],\
+ "Min:", min(g_snrs), "Max:", max(g_snrs)
+ print " B SNR:", rgb_snrs[2],\
+ "Min:", min(b_snrs), "Max:", max(b_snrs)
+
+ for chan in range(3):
+ snrs[chan].append(rgb_snrs[chan])
# Draw a plot.
- for chan in range(3):
- line = []
- for nr_mode in range(5):
- line.append(variances[nr_mode][chan])
- pylab.plot(range(5), line, "rgb"[chan])
+ for channel in range(3):
+ pylab.plot(range(5), snrs[channel], "rgb"[channel])
- matplotlib.pyplot.savefig("%s_plot_%s_variances.png" %
+ matplotlib.pyplot.savefig("%s_plot_%s_SNRs.png" %
(NAME, reprocess_format))
assert(nr_modes_reported == [0,1,2,3,4])
for j in range(3):
- # Smaller variance is better
+ # Larger is better
# Verify OFF(0) is not better than FAST(1)
- assert(variances[0][j] >
- variances[1][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][1] + SNR_TOLERANCE)
# Verify FAST(1) is not better than HQ(2)
- assert(variances[1][j] >
- variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][1] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify HQ(2) is better than OFF(0)
- assert(variances[0][j] > variances[2][j])
+ assert(snrs[j][0] < snrs[j][2])
if its.caps.noise_reduction_mode(props, 3):
# Verify OFF(0) is not better than MINIMAL(3)
- assert(variances[0][j] >
- variances[3][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][0] <
+ snrs[j][3] + SNR_TOLERANCE)
# Verify MINIMAL(3) is not better than HQ(2)
- assert(variances[3][j] >
- variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
+ assert(snrs[j][3] <
+ snrs[j][2] + SNR_TOLERANCE)
# Verify ZSL(4) is close to MINIMAL(3)
- assert(numpy.isclose(variances[4][j], variances[3][j],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][3],
+ atol=SNR_TOLERANCE))
else:
# Verify ZSL(4) is close to OFF(0)
- assert(numpy.isclose(variances[4][j], variances[0][j],
- RELATIVE_ERROR_TOLERANCE))
+ assert(numpy.isclose(snrs[j][4], snrs[j][0],
+ atol=SNR_TOLERANCE))
if __name__ == '__main__':
main()
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
index 33e7763..268b64a 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_dng.py
@@ -31,6 +31,12 @@
cam.do_3a()
req = its.objects.auto_capture_request()
+ max_dng_size = \
+ its.objects.get_available_output_sizes("raw", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_dng_size)[0]
+ out_surfaces = [{"format":"dng"},
+ {"format":"yuv", "width":w, "height":h}]
cap_dng, cap_yuv = cam.do_capture(req, cam.CAP_DNG_YUV)
img = its.image.convert_capture_to_rgb_image(cap_yuv)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
index 9ce8d76..78378eb 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_jpeg.py
@@ -27,13 +27,17 @@
THRESHOLD_MAX_RMS_DIFF = 0.01
- fmt_yuv = {"format":"yuv"}
- fmt_jpeg = {"format":"jpeg"}
-
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
its.caps.skip_unless(its.caps.compute_target_exposure(props))
+ max_jpeg_size = \
+ its.objects.get_available_output_sizes("jpeg", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_jpeg_size)[0]
+ fmt_yuv = {"format":"yuv", "width":w, "height":h}
+ fmt_jpeg = {"format":"jpeg"}
+
# Use a manual request with a linear tonemap so that the YUV and JPEG
# should look the same (once converted by the its.image module).
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
index f13801b..bfa6a28 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw.py
@@ -38,7 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
- cap_raw, cap_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
+ max_raw_size = \
+ its.objects.get_available_output_sizes("raw", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw_size)[0]
+ out_surfaces = [{"format":"raw"},
+ {"format":"yuv", "width":w, "height":h}]
+ cap_raw, cap_yuv = cam.do_capture(req, out_surfaces)
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
index e52946d..322af10 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw10.py
@@ -38,8 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
+ max_raw10_size = \
+ its.objects.get_available_output_sizes("raw10", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw10_size)[0]
cap_raw, cap_yuv = cam.do_capture(req,
- [{"format":"raw10"}, {"format":"yuv"}])
+ [{"format":"raw10"},
+ {"format":"yuv", "width":w, "height":h}])
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
index c5c3c73..b3cca0b 100644
--- a/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
+++ b/apps/CameraITS/tests/scene1/test_yuv_plus_raw12.py
@@ -38,8 +38,13 @@
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
req = its.objects.manual_capture_request(s, e, True, props)
+ max_raw12_size = \
+ its.objects.get_available_output_sizes("raw12", props)[0]
+ w,h = its.objects.get_available_output_sizes(
+ "yuv", props, (1920, 1080), max_raw12_size)[0]
cap_raw, cap_yuv = cam.do_capture(req,
- [{"format":"raw12"}, {"format":"yuv"}])
+ [{"format":"raw12"},
+ {"format":"yuv", "width":w, "height":h}])
img = its.image.convert_capture_to_rgb_image(cap_yuv)
its.image.write_image(img, "%s_yuv.jpg" % (NAME), True)
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index 73834cb..e96a9ee 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -53,22 +53,28 @@
"""
NAME = os.path.basename(__file__).split(".")[0]
+ NUM_SAMPLES = 4
req = its.objects.manual_capture_request(sensitivity, exp)
req["android.lens.focusDistance"] = fd
req["android.edge.mode"] = edge_mode
if (reprocess_format != None):
req["android.reprocess.effectiveExposureFactor"] = 1.0
- cap = cam.do_capture(req, out_surface, reprocess_format)
- img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
- its.image.write_image(img, "%s_edge=%d_reprocess_fmt_%s.jpg" %
- (NAME, edge_mode, reprocess_format))
- tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ sharpness_list = []
+ for n in range(NUM_SAMPLES):
+ cap = cam.do_capture(req, out_surface, reprocess_format)
+ img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
+ if n == 0:
+ its.image.write_image(img, "%s_reprocess_fmt_%s_edge=%d.jpg" %
+ (NAME, reprocess_format, edge_mode))
+ res_edge_mode = cap["metadata"]["android.edge.mode"]
+ tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
+ sharpness_list.append(its.image.compute_image_sharpness(tile))
ret = {}
- ret["edge_mode"] = cap["metadata"]["android.edge.mode"]
- ret["sharpness"] = its.image.compute_image_sharpness(tile)
+ ret["edge_mode"] = res_edge_mode
+ ret["sharpness"] = numpy.mean(sharpness_list)
return ret
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 8cec7ea..34246cc 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -41,7 +41,7 @@
LOCAL_PACKAGE_NAME := CtsVerifier
-LOCAL_AAPT_FLAGS += --version-name "6.0_r0 $(BUILD_NUMBER)"
+LOCAL_AAPT_FLAGS += --version-name "6.0_r1 $(BUILD_NUMBER)"
LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni libaudioloopback_jni
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 5c188b7..5e8ab90 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -363,6 +363,7 @@
<meta-data android:name="test_category" android:value="@string/test_category_security" />
<meta-data android:name="test_excluded_features"
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.fingerprint" />
</activity>
<activity android:name=".security.ScreenLockBoundKeysTest"
android:label="@string/sec_lock_bound_key_test"
@@ -753,7 +754,7 @@
android:screenOrientation="locked" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+ <category android:name="android.cts.intent.category.MANUAL_TEST_disabled"/>
</intent-filter>
<meta-data
@@ -762,8 +763,6 @@
<meta-data
android:name="test_required_features"
android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.gyroscope:android.hardware.sensor.compass:android.hardware.camera.any" />
- <meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.television" />
</activity>
<activity
android:name=".sensors.RVCVRecordActivity"
@@ -1397,6 +1396,13 @@
</intent-filter>
</activity-alias>
+ <activity android:name=".managedprovisioning.AuthenticationBoundKeyTestActivity">
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".managedprovisioning.ByodFlowTestActivity"
android:launchMode="singleTask"
android:label="@string/provisioning_byod">
@@ -1424,6 +1430,8 @@
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW" />
<action android:name="com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>
@@ -1451,11 +1459,87 @@
<activity android:name=".managedprovisioning.CrossProfileTestActivity">
<intent-filter>
- <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE" />
- <!-- We need to have at least one activity listening to this intent in the parent
- to test if it is forwarded from the managed profile to the parent -->
+ <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK" />
+ <!-- We need to have at least one activity listening to these intents on the device
+ to test if these are forwarded from the managed profile to the parent or
+ the other way around. -->
<action android:name="android.provider.MediaStore.RECORD_SOUND" />
- <category android:name="android.intent.category.DEFAULT"></category>
+ <action android:name="android.speech.action.RECOGNIZE_SPEECH" />
+ <action android:name="android.app.action.SET_NEW_PASSWORD" />
+ <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
+ <action android:name="android.intent.action.WEB_SEARCH" />
+ <action android:name="android.intent.action.VIEW_DOWNLOADS" />
+ <action android:name="android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" />
+ <action android:name="android.settings.SHOW_INPUT_METHOD_PICKER" />
+ <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+ <action android:name="com.android.settings.TTS_SETTINGS" />
+ <action android:name="android.settings.ZEN_MODE_SETTINGS" />
+ <action android:name="android.settings.BATTERY_SAVER_SETTINGS" />
+ <action android:name="android.settings.INPUT_METHOD_SETTINGS" />
+ <action android:name="android.settings.INPUT_METHOD_SUBTYPE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <action android:name="android.intent.action.SEND_MULTIPLE" />
+ <data android:mimeType="*/*" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.GET_CONTENT" />
+ <action android:name="android.intent.action.OPEN_DOCUMENT" />
+ <data android:mimeType="*/*" />
+ <category android:name="android.intent.category.OPENABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.intent.action.SENDTO" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ <data android:scheme="mailto" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.intent.action.CALL" />
+ <action android:name="android.intent.action.DIAL" />
+ <action android:name="android.intent.action.CALL_PRIVILEGED" />
+ <action android:name="android.intent.action.CALL_EMERGENCY" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.INSERT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="content" />
+ <data android:mimeType="*/*" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" android:host="com.android.cts.verifier" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ <data android:mimeType="video/mp4" />
+ <data android:mimeType="audio/*" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ <data android:scheme="geo" />
+ <data android:scheme="market" />
</intent-filter>
</activity>
@@ -1573,6 +1657,18 @@
android:value="android.software.live_tv" />
</activity>
+ <activity android:name=".tv.AppLinkTestActivity"
+ android:label="@string/tv_app_link_test"
+ android:launchMode="singleTask">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+ <meta-data android:name="test_required_features"
+ android:value="android.software.live_tv" />
+ </activity>
+
<activity android:name=".screenpinning.ScreenPinningTestActivity"
android:label="@string/screen_pinning_test">
<intent-filter>
@@ -1612,30 +1708,46 @@
<meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
</activity>
- <activity android:name=".audio.AudioDeviceNotificationsActivity"
- android:label="@string/audio_devices_notifications_test">
+ <activity android:name=".audio.AudioOutputDeviceNotificationsActivity"
+ android:label="@string/audio_out_devices_notifications_test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_audio" />
- <!--
- <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
- -->
+ <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
</activity>
- <activity android:name=".audio.AudioRoutingNotificationsActivity"
- android:label="@string/audio_routingnotifications_test">
+ <activity android:name=".audio.AudioInputDeviceNotificationsActivity"
+ android:label="@string/audio_in_devices_notifications_test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_audio" />
- <!--
<meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
- -->
</activity>
+ <activity android:name=".audio.AudioOutputRoutingNotificationsActivity"
+ android:label="@string/audio_output_routingnotifications_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
+ </activity>
+
+ <activity android:name=".audio.AudioInputRoutingNotificationsActivity"
+ android:label="@string/audio_input_routingnotifications_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+ </activity>
+
<activity android:name=".audio.AudioLoopbackActivity"
android:label="@string/audio_loopback_test">
<intent-filter>
@@ -1644,6 +1756,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_audio" />
<meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
<meta-data android:name="test_excluded_features" android:value="android.hardware.type.watch" />
<meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
</activity>
diff --git a/apps/CtsVerifier/jni/verifier/Android.mk b/apps/CtsVerifier/jni/verifier/Android.mk
index da4687d..4840e62 100644
--- a/apps/CtsVerifier/jni/verifier/Android.mk
+++ b/apps/CtsVerifier/jni/verifier/Android.mk
@@ -25,8 +25,11 @@
LOCAL_SRC_FILES := \
CtsVerifierJniOnLoad.cpp \
- com_android_cts_verifier_os_FileUtils.cpp
+ com_android_cts_verifier_camera_StatsImage.cpp \
+ com_android_cts_verifier_os_FileUtils.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+LOCAL_SHARED_LIBRARIES := liblog
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp b/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
index 81e5690..399275b 100644
--- a/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
+++ b/apps/CtsVerifier/jni/verifier/CtsVerifierJniOnLoad.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@
#include <stdio.h>
extern int register_com_android_cts_verifier_os_FileUtils(JNIEnv*);
+extern int register_com_android_cts_verifier_camera_its_StatsImage(JNIEnv*);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
@@ -30,5 +31,9 @@
return JNI_ERR;
}
+ if (register_com_android_cts_verifier_camera_its_StatsImage(env)) {
+ return JNI_ERR;
+ }
+
return JNI_VERSION_1_4;
}
diff --git a/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp b/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp
new file mode 100644
index 0000000..16dff85
--- /dev/null
+++ b/apps/CtsVerifier/jni/verifier/com_android_cts_verifier_camera_StatsImage.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ITS-StatsImage-JNI"
+// #define LOG_NDEBUG 0
+#include <android/log.h>
+#include <utils/Log.h>
+
+#include <jni.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <string.h>
+
+jfloatArray com_android_cts_verifier_camera_its_computeStatsImage(JNIEnv* env, jobject thiz,
+ jbyteArray img, jint width, jint height, jint gridWidth, jint gridHeight)
+{
+ int bufSize = (int)(env->GetArrayLength(img));
+ unsigned char *buf = (unsigned char*)env->GetByteArrayElements(img, /*is_copy*/NULL);
+
+ // Size of the raw image.
+ const int w = width;
+ const int h = height;
+ // Size of each grid cell.
+ const int gw = gridWidth;
+ const int gh = gridHeight;
+ // Number of grid cells (rounding down to full cells only at right+bottom edges).
+ const int ngx = w / gw;
+ const int ngy = h / gh;
+
+ float *mean = new float[ngy*ngx*4];
+ float *var = new float[ngy*ngx*4];
+ for (int gy = 0; gy < ngy; gy++) {
+ for (int gx = 0; gx < ngx; gx++) {
+ float sum[4] = {0};
+ float sumSq[4] = {0};
+ int count[4] = {0};
+ for (int y = gy*gh; y < (gy+1)*gh; y++) {
+ int chnOffset = (y & 0x1) * 2;
+ unsigned char *pbuf = buf + 2*y*w + 2*gx*gw;
+ for (int x = gx*gw; x < (gx+1)*gw; x++) {
+ // input is RAW16
+ int byte0 = *pbuf++;
+ int byte1 = *pbuf++;
+ int pixelValue = (byte1 << 8) | byte0;
+ int ch = chnOffset + (x & 1);
+ sum[ch] += pixelValue;
+ sumSq[ch] += pixelValue * pixelValue;
+ count[ch] += 1;
+ }
+ }
+ for (int ch = 0; ch < 4; ch++) {
+ float m = (float)sum[ch] / count[ch];
+ float mSq = (float)sumSq[ch] / count[ch];
+ mean[gy*ngx*4 + gx*4 + ch] = m;
+ var[gy*ngx*4 + gx*4 + ch] = mSq - m*m;
+ }
+ }
+ }
+
+ jfloatArray ret = env->NewFloatArray(ngx*ngy*4*2);
+ env->SetFloatArrayRegion(ret, 0, ngx*ngy*4, (float*)mean);
+ env->SetFloatArrayRegion(ret, ngx*ngy*4, ngx*ngy*4, (float*)var);
+ delete [] mean;
+ delete [] var;
+ return ret;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "computeStatsImage", "([BIIII)[F",
+ (void *) com_android_cts_verifier_camera_its_computeStatsImage },
+};
+
+int register_com_android_cts_verifier_camera_its_StatsImage(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("com/android/cts/verifier/camera/its/StatsImage");
+
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/apps/CtsVerifier/res/drawable/app_link_img.png b/apps/CtsVerifier/res/drawable/app_link_img.png
new file mode 100644
index 0000000..851fc6f
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/app_link_img.png
Binary files differ
diff --git a/apps/CtsVerifier/res/layout/audio_dev_notify.xml b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
index 98dbd8b..ceedf1c 100644
--- a/apps/CtsVerifier/res/layout/audio_dev_notify.xml
+++ b/apps/CtsVerifier/res/layout/audio_dev_notify.xml
@@ -13,19 +13,51 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/scrollView"
+ >
+
+<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="10dip"
+ android:padding="20dp"
android:orientation="vertical">
- <TextView
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
+ </LinearLayout>
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:gravity="bottom"
- android:id="@+id/info_text"
- android:text="@string/audio_devices_notification_instructions" />
+ android:id="@+id/info_text"/>
<LinearLayout
android:layout_width="match_parent"
@@ -51,4 +83,5 @@
<include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
index 69e3bc7..c1b62af 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
@@ -13,60 +13,105 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:orientation="vertical"
+>
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:orientation="vertical">
+ android:layout_height="match_parent"
+ android:id="@+id/scrollView"
+ >
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:gravity="bottom"
- android:id="@+id/info_text"
- android:text="@string/audio_frequency_line_instructions" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_frequency_line_plug_ready_btn"
- android:text="@string/audio_frequency_line_plug_ready_btn"/>
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:id="@+id/audio_frequency_line_layout">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_line_test_btn"
- android:id="@+id/audio_frequency_line_test_btn"/>
-
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/audio_frequency_line_progress_bar"/>
- </LinearLayout>
-
- <TextView
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/audio_frequency_line_results_text"
- android:id="@+id/audio_frequency_line_results_text"/>
+ android:orientation="vertical"
+ >
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
- </LinearLayout>
- </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
- <include layout="@layout/pass_fail_buttons" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
+
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/info_text"
+ android:text="@string/audio_frequency_line_instructions" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_line_plug_ready_btn"
+ android:text="@string/audio_frequency_line_plug_ready_btn" />
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:id="@+id/audio_frequency_line_layout"
+ >
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_line_test_btn"
+ android:id="@+id/audio_frequency_line_test_btn" />
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_line_progress_bar" />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_line_results_text"
+ android:id="@+id/audio_frequency_line_results_text" />
+
+ </LinearLayout>
+ </LinearLayout>
+
+ <include layout="@layout/pass_fail_buttons" />
+ </LinearLayout>
+ </ScrollView>
</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
index 10b0003..db52998 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
@@ -18,116 +18,151 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dip"
- android:orientation="vertical">
+ android:orientation="vertical"
+>
<ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/scrollView">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/scrollView"
+ >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ >
- <LinearLayout
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+
+ <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:id="@+id/info_text"
- android:text="@string/audio_frequency_mic_instructions"/>
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:id="@+id/audio_frequency_mic_progress_bar"/>
- </LinearLayout>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_frequency_mic_speakers_ready_btn"
- android:text="@string/audio_frequency_mic_speakers_ready_btn"/>
+ </LinearLayout>
- <TextView
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/info_text"
+ android:text="@string/audio_frequency_mic_instructions" />
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/audio_frequency_mic_progress_bar" />
+ </LinearLayout>
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_mic_speakers_ready_btn"
+ android:text="@string/audio_frequency_mic_speakers_ready_btn" />
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:gravity="bottom"
android:id="@+id/audio_frequency_mic_speakers_ready_status"
- android:text="@string/audio_frequency_mic_speakers_ready_status"/>
+ android:text="@string/audio_frequency_mic_speakers_ready_status" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:id="@+id/audio_frequency_mic_layout_test1">
+ android:id="@+id/audio_frequency_mic_layout_test1"
+ >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_mic_instructions2"
- android:id="@+id/audio_frequency_mic_instructions2"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_mic_instructions2"
+ android:id="@+id/audio_frequency_mic_instructions2" />
- <Button
+ <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/audio_frequency_mic_test1_btn"
- android:id="@+id/audio_frequency_mic_test1_btn"/>
+ android:id="@+id/audio_frequency_mic_test1_btn" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/audio_frequency_mic_results_text"
- android:id="@+id/audio_frequency_mic_results1_text"/>
- </LinearLayout>
+ android:id="@+id/audio_frequency_mic_results1_text" />
+ </LinearLayout>
- <LinearLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:id="@+id/audio_frequency_mic_layout_test2a">
+ android:id="@+id/audio_frequency_mic_layout_test2a"
+ >
- <Button
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_mic_mic_ready_btn"
+ android:text="@string/audio_frequency_mic_mic_ready_btn" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_mic_usb_status"
+ android:id="@+id/audio_frequency_mic_usb_status" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_frequency_mic_mic_ready_btn"
- android:text="@string/audio_frequency_mic_mic_ready_btn"/>
+ android:layout_height="match_parent"
+ android:id="@+id/audio_frequency_mic_layout_test2b"
+ >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_mic_usb_status"
- android:id="@+id/audio_frequency_mic_usb_status"/>
- </LinearLayout>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_mic_test2_btn"
+ android:id="@+id/audio_frequency_mic_test2_btn" />
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/audio_frequency_mic_layout_test2b">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_mic_results_text"
+ android:id="@+id/audio_frequency_mic_results_text" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_mic_test2_btn"
- android:id="@+id/audio_frequency_mic_test2_btn"/>
+ </LinearLayout>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_mic_results_text"
- android:id="@+id/audio_frequency_mic_results_text"/>
-
+ <include layout="@layout/pass_fail_buttons" />
</LinearLayout>
-
- <include layout="@layout/pass_fail_buttons"/>
- </LinearLayout>
- </ScrollView>
+ </ScrollView>
</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml b/apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
similarity index 61%
copy from apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
copy to apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
index cef30d6..60a12ef 100644
--- a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
+++ b/apps/CtsVerifier/res/layout/audio_input_routingnotifications_test.xml
@@ -14,52 +14,51 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/scrollView"
+ >
+
+<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="10dip"
+ android:padding = "20dp"
android:orientation="vertical">
- <TextView
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
+ </LinearLayout>
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:gravity="bottom"
android:id="@+id/info_text"
- android:text="@string/audio_dev_routingnotification_instructions" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:id="@+id/audioTrackRoutingLayout">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/audio_routingnotification_playHeader"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_audioTrack_change"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_playBtn"
- android:text="@string/audio_routingnotification_playBtn"/>
-
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_playStopBtn"
- android:text="@string/audio_routingnotification_playStopBtn"/>
- </LinearLayout>
- </LinearLayout>
+ android:text="@string/audio_input_routingnotification_instructions" />
<LinearLayout
android:layout_width="match_parent"
@@ -96,4 +95,5 @@
<include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/audio_loopback_activity.xml b/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
index 626ac4f..815f2bc 100644
--- a/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_loopback_activity.xml
@@ -13,71 +13,120 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:orientation="vertical">
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:orientation="vertical"
+>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:gravity="bottom"
- android:id="@+id/info_text"
- android:text="@string/audio_loopback_instructions" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_plug_ready_btn"
- android:text="@string/audio_loopback_plug_ready_btn"/>
-
- <LinearLayout
- android:orientation="vertical"
+ <ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/audio_loopback_layout">
+ android:id="@+id/scrollView"
+ >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_instructions2"
- android:id="@+id/audio_loopback_instructions2"/>
-
- <SeekBar
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_level_seekbar"/>
+ android:orientation="vertical"
+ >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_level_text"
- android:id="@+id/audio_loopback_level_text"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_test_btn"
- android:id="@+id/audio_loopback_test_btn"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/audio_loopback_progress_bar"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_loopback_results_text"
- android:id="@+id/audio_loopback_results_text"/>
- </LinearLayout>
- </LinearLayout>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
- <include layout="@layout/pass_fail_buttons" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/audio_loopback_headset_port"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/info_text"
+ android:text="@string/audio_loopback_instructions" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_loopback_plug_ready_btn"
+ android:text="@string/audio_loopback_plug_ready_btn" />
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/audio_loopback_layout"
+ >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_instructions2"
+ android:id="@+id/audio_loopback_instructions2" />
+
+ <SeekBar
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_loopback_level_seekbar" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_level_text"
+ android:id="@+id/audio_loopback_level_text" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_test_btn"
+ android:id="@+id/audio_loopback_test_btn" />
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_loopback_progress_bar" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_loopback_results_text"
+ android:id="@+id/audio_loopback_results_text" />
+ </LinearLayout>
+
+ </LinearLayout>
+ <include layout="@layout/pass_fail_buttons" />
+ </LinearLayout>
+ </ScrollView>
</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml b/apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
similarity index 61%
rename from apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
rename to apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
index cef30d6..d039691 100644
--- a/apps/CtsVerifier/res/layout/audio_routingnotifications_test.xml
+++ b/apps/CtsVerifier/res/layout/audio_output_routingnotifications_test.xml
@@ -14,19 +14,52 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/scrollView"
+ >
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="10dip"
+ android:padding="20dp"
android:orientation="vertical">
- <TextView
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/audio_general_headset_port_exists"
+ android:text="@string/audio_general_headset_port_exists" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_no"
+ android:text="@string/audio_general_headset_no" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_general_headset_yes"
+ android:text="@string/audio_general_headset_yes" />
+
+ </LinearLayout>
+
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:gravity="bottom"
android:id="@+id/info_text"
- android:text="@string/audio_dev_routingnotification_instructions" />
+ android:text="@string/audio_output_routingnotification_instructions" />
<LinearLayout
android:layout_width="match_parent"
@@ -61,39 +94,7 @@
</LinearLayout>
</LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:id="@+id/audioRecordRoutingLayout">
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/audio_routingnotification_recHeader"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_audioRecord_change"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_recordBtn"
- android:text="@string/audio_routingnotification_recBtn"/>
-
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/audio_routingnotification_recordStopBtn"
- android:text="@string/audio_routingnotification_recStopBtn"/>
- </LinearLayout>
- </LinearLayout>
-
<include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/keychain_main.xml b/apps/CtsVerifier/res/layout/keychain_main.xml
index 01eb255..3f695cd 100644
--- a/apps/CtsVerifier/res/layout/keychain_main.xml
+++ b/apps/CtsVerifier/res/layout/keychain_main.xml
@@ -24,22 +24,36 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:padding="10dip" >
+ android:padding="10dip">
- <TextView
- android:id="@+id/test_instruction"
- style="@style/InstructionsFont"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0" />
-
- <TextView
- android:id="@+id/test_log"
+ <ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:layout_gravity="bottom"
- android:orientation="vertical" />
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:id="@+id/test_messages"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/test_instruction"
+ style="@style/InstructionsFont"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0" />
+
+ <TextView
+ android:id="@+id/test_log"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical" />
+
+ </LinearLayout>
+ </ScrollView>
<LinearLayout
android:id="@+id/action_buttons"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 77566a3..d8a96eb 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1277,7 +1277,25 @@
<string name="provisioning_byod_no_video_capture_resolver">No video capture app present. Skip test.</string>
<string name="provisioning_byod_no_audio_capture_resolver">No audio capture app present. Skip test.</string>
<string name="provisioning_byod_capture_media_error">Error while capturing media from managed profile.</string>
+ <string name="provisioning_byod_capture_image_error">Error while capturing image from managed profile.</string>
+ <string name="provisioning_byod_auth_bound_key">Autentication-boud keys</string>
+ <string name="provisioning_byod_auth_bound_key_info">
+ This test verifies keystore cryptographic keys can be bound to device credentials.
+ These keys should only be available if there was a recent enough authentication.
+ </string>
+ <string name="provisioning_byod_auth_bound_key_instruction">
+ This test verifies keystore cryptographic keys can be bound to device lockscreen challenge or fingerprints (if available).
+ These keys should only be available if there was a recent enough authentication. \n
+
+ 1. Press "Set up" to open Security settings. Create a lockscreen password and if available, enroll a fingerprint.\n
+ 2. Go through the list of tests.\n
+ 3. Mark the overall test pass or fail.\n
+ 4. Once the set of tests are completed, remove the lockscreen challenge.
+ </string>
+ <string name="provisioning_byod_auth_bound_key_set_up">Set up</string>
+ <string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
+ <string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
<!-- Strings for DeskClock -->
<string name="deskclock_tests">Alarms and Timers Tests</string>
<string name="deskclock_tests_info">
@@ -1436,12 +1454,13 @@
<string name="provisioning_byod_profile_visible">Profile-aware accounts settings</string>
<string name="provisioning_byod_admin_visible">Profile-aware device administrator settings</string>
<string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
- <string name="provisioning_byod_cross_profile">Open app cross profiles</string>
- <string name="provisioning_byod_cross_profile_app_personal">
- You selected the CTS Verifier option.
- </string>
+ <string name="provisioning_byod_cross_profile_from_personal">Open app cross profiles from the personal side</string>
+ <string name="provisioning_byod_cross_profile_from_work">Open app cross profiles from the work side</string>
+ <string name="provisioning_app_linking">App links from the work side</string>
+ <string name="provisioning_byod_cross_profile_app_personal">You selected the personal option.</string>
<string name="provisioning_byod_cross_profile_app_work">You selected the Work option.</string>
- <string name="provisioning_byod_cross_profile_instruction">
+ <string name="provisioning_byod_cross_profile_app_ctsverifier"> You selected the ctsverifier option </string>
+ <string name="provisioning_byod_cross_profile_from_personal_instruction">
Please press the Go button to start an action.\n
\n
You should be asked to choose either \"CTS Verifier\" or \"Work\" to complete the action.
@@ -1449,6 +1468,25 @@
\n
Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
</string>
+ <string name="provisioning_byod_cross_profile_from_work_instruction">
+ Please press the Go button to start an action.\n
+ \n
+ You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.
+ Pressing either should bring up a page stating your choice.\n
+ \n
+ Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+ </string>
+ <string name="provisioning_byod_app_linking_instruction">
+ Please press the Go button to start an action.\n
+ \n
+ You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.\n
+ - If you choose \"CTS Verifier\", you should see a page stating your chose \"CTS Verifier\".\n
+ - If you choose \"Personal\", you should be presented with another dialog between \"CTS Verifier\"
+ and some other apps. In this case, you should choose \"CTS verifier\".\n
+ You should then see a page stating you chose \"Personal\".\n
+ \n
+ Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+ </string>
<string name="provisioning_byod_keyguard_disabled_features">Keyguard disabled features</string>
<string name="provisioning_byod_keyguard_disabled_features_info">
This test exercises Keyguard Disabled Features. Follow instructions above.
@@ -1640,6 +1678,7 @@
<string name="provisioning_byod_send_share_intent">Send share intent</string>
<string name="provisioning_byod_cannot_resolve_beam_activity">Cannot find beam activity</string>
+ <string name="test_failed_cannot_start_intent">Cannot start the given intent.</string>
<string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
<string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
<string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
@@ -1875,7 +1914,6 @@
Do you see the programs named \"Dummy Program\" and their descriptions
"Dummy Program Description" in the EPG?
</string>
- <string name="tv_input_discover_test_yes">Yes</string>
<string name="tv_parental_control_test">TV app parental controls test</string>
<string name="tv_parental_control_test_info">
@@ -1964,6 +2002,24 @@
The playback position should be moved to the next position.
</string>
+ <string name="tv_app_link_test">TV app app-link test</string>
+ <string name="tv_app_link_test_info">
+ Verify that the bundled TV app supports linking to channel apps. If TV input service provides
+ links for its specific channels, TV app should show the links in a proper format.
+ </string>
+ <string name="tv_app_link_test_select_app_link">
+ Select the \"Launch TV app\" button, then check if you can see a menu with \"Cts App-Link Text\"
+ text in red background. If you see the link, select it to follow the link.
+ </string>
+ <string name="tv_app_link_test_verify_link_clicked">
+ The app-link must have been clicked and the activity should be changed correctly.
+ </string>
+ <string name="tv_input_link_test_verify_link_interface">
+ Do you see the app-link card similar to the image on the left?\n
+ 1) You should see the poster art image, but the color could be differ.\n
+ 2) You should see the text \"Cts App-Link Text\".\n
+ </string>
+
<string name="overlay_view_text">Overlay View Dummy Text</string>
<string name="fake_rating">Fake</string>
@@ -1984,25 +2040,34 @@
<string name="error_screen_pinning_did_not_exit">Screen was not unpinned.</string>
<string name="error_screen_pinning_couldnt_exit">Could not exit screen pinning through API.</string>
- <!-- Audio Devices Notifcations Test -->
- <string name="audio_devices_notifications_test">Audio Devices Notifications Test</string>
- <string name="audio_devices_notification_instructions">
+ <!-- Audio Devices Notifcations Tests -->
+ <string name="audio_out_devices_notifications_test">Audio Output Devices Notifications Test</string>
+ <string name="audio_out_devices_notification_instructions">
Click the "Clear Messages" button then connect and disconnect a wired headset.
Note if the appropriate notification messages appear below.
</string>
+ <string name="audio_in_devices_notifications_test">Audio Input Devices Notifications Test</string>
+ <string name="audio_in_devices_notification_instructions">
+ Click the "Clear Messages" button then connect and disconnect a microphone or wired headset.
+ Note if the appropriate notification messages appear below.
+ </string>
<string name="audio_dev_notification_clearmsgs">Clear Messages</string>
<string name="audio_dev_notification_connectMsg">CONNECT DETECTED</string>
<string name="audio_dev_notification_disconnectMsg">DISCONNECT DETECTED</string>
- <!-- Audio Routing Notifcations Test -->
- <string name="audio_routingnotifications_test">Audio Routing Notifications Test</string>
- <string name="audio_dev_routingnotification_instructions">
- Click on the "Play" button in the AudioTrack Routing Notifictions section below to
+ <string name="audio_input_routingnotifications_test">Audio Input Routing Notifications Test</string>
+ <string name="audio_input_routingnotification_instructions">
+ Click on the "Record" button in the AudioRecord Routing Notifications section below to
+ start recording. Insert a wired headset or microphone. Observe a message acknowledging the
+ rerouting event below. Remove the wired headset and observe the new routing message.
+ Click on the "Stop" button to stop recording.\n
+ </string>
+ <string name="audio_output_routingnotifications_test">Audio Output Routing Notifications Test</string>
+ <string name="audio_output_routingnotification_instructions">
+ Click on the "Play" button in the AudioTrack Routing Notifications section below to
start (silent) playback. Insert a wired headset. Observe a message acknowledging the
rerouting event below. Remove the wired headset and observe the new routing message.
Click on the "Stop" button to stop playback.\n
- Repeat the process with "Record" and "Stop" button in the AudioRecord Routing
- Notifications section below.
</string>
<string name="audio_routingnotification_playBtn">Play</string>
<string name="audio_routingnotification_playStopBtn">Stop</string>
@@ -2013,14 +2078,19 @@
<string name="audio_routingnotification_trackRoutingMsg">AudioTrack rerouting</string>
<string name="audio_routingnotification_recordRoutingMsg">AudioRecord rerouting</string>
+ <!-- Audio general text -->
+ <string name="audio_general_headset_port_exists">Does this device have a headset port?</string>
+ <string name="audio_general_headset_no">No</string>
+ <string name="audio_general_headset_yes">Yes</string>
+
<!-- Audio Loopback Latency Test -->
<string name="audio_loopback_test">Audio Loopback Latency Test</string>
<string name="audio_loopback_info">
- This test requires the Loopback Plug. Please connect a Loopback Plug on the headset
+ This test requires the Loopback Plug. Please connect a Loopback Plug into the headset
connector, and proceed with the instructions on the screen.
The system will measure the input-output audio latency by injecting a pulse on the output,
and computing the distance between replicas of the pulse.
- You can vary the Audio Level slider to ensure the pulse will feed back at adecuate levels.
+ You can vary the Audio Level slider to ensure the pulse will feed back at adequate levels.
Repeat until a confidence level >= 0.6 is achieved.
</string>
<string name="audio_loopback_instructions">
@@ -2055,7 +2125,7 @@
<string name="audio_frequency_speaker_test">Audio Frequency Speaker Test</string>
<string name="audio_frequency_speaker_info">
This test requires an external USB reference microphone. Please connect the USB microphone and proceed with the instructions on the screen.
- The system will measure frequency response of the left and right speakers (if there are two speakers), or twice the response of the mono speaker.
+ The system will measure frequency response of the left and right speakers (if there are two speakers), or the response of the mono speaker twice.
</string>
<string name="audio_frequency_speaker_instructions">
Please connect an USB reference microphone and press "USB Reference microphone ready"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index 789effa..91b8d93 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.database.DataSetObserver;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -41,6 +42,7 @@
* Instructions are shown on top of the screen and a test preparation button is provided.
*/
public abstract class DialogTestListActivity extends PassFailButtons.TestListActivity {
+ private final String TAG = "DialogTestListActivity";
private final int mLayoutId;
private final int mTitleStringId;
private final int mInfoStringId;
@@ -170,7 +172,13 @@
mCurrentTestPosition = position;
((DialogTestListItem)test).performTest(this);
} else {
- super.handleItemClick(l, v, position, id);
+ try {
+ super.handleItemClick(l, v, position, id);
+ } catch (ActivityNotFoundException e) {
+ Log.d(TAG, "handleItemClick() threw exception: ", e);
+ setTestResult(test, TestResult.TEST_RESULT_FAILED);
+ showToast(R.string.test_failed_cannot_start_intent);
+ }
}
}
@@ -196,7 +204,7 @@
// do nothing, override in subclass if needed
}
- protected void setTestResult(DialogTestListItem test, int result) {
+ protected void setTestResult(TestListAdapter.TestListItem test, int result) {
// Bundle result in an intent to feed into handleLaunchTestResult
Intent resultIntent = new Intent();
TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
index d3e2571..508fae0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -64,6 +64,9 @@
OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Context mContext;
+ Button mHeadsetPortYes;
+ Button mHeadsetPortNo;
+
Button mLoopbackPlugReady;
LinearLayout mLinearLayout;
Button mTestButton;
@@ -116,6 +119,20 @@
Log.i(TAG, "audio loopback test");
startAudioTest();
break;
+ case R.id.audio_general_headset_yes:
+ Log.i(TAG, "User confirms Headset Port existence");
+ mLoopbackPlugReady.setEnabled(true);
+ recordHeasetPortFound(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
+ case R.id.audio_general_headset_no:
+ Log.i(TAG, "User denies Headset Port existence");
+ recordHeasetPortFound(false);
+ getPassButton().setEnabled(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
}
}
}
@@ -127,8 +144,14 @@
mContext = this;
+ mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+ mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+ mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+ mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_line_plug_ready_btn);
mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+ mLoopbackPlugReady.setEnabled(false);
mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_line_layout);
mTestButton = (Button)findViewById(R.id.audio_frequency_line_test_btn);
mTestButton.setOnClickListener(mBtnClickListener);
@@ -479,6 +502,14 @@
Log.v(TAG, "Results Recorded");
}
+ private void recordHeasetPortFound(boolean found) {
+ getReportLog().addValue(
+ "User Reported Headset Port",
+ found ? 1.0 : 0,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ }
+
private void startRecording() {
synchronized (mRecordingLock) {
mIsRecording = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
index b37a721..03d84e1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -72,6 +72,9 @@
final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Context mContext;
+ Button mHeadsetPortYes;
+ Button mHeadsetPortNo;
+
Button mSpeakersReady; //user signal to have connected external speakers
Button mTest1Button; //execute test 1
Button mUsbMicReady; //user signal to have connected USB Microphone
@@ -137,6 +140,20 @@
case R.id.audio_frequency_mic_test2_btn:
startTest2();
break;
+ case R.id.audio_general_headset_yes:
+ Log.i(TAG, "User confirms Headset Port existence");
+ mSpeakersReady.setEnabled(true);
+ recordHeasetPortFound(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
+ case R.id.audio_general_headset_no:
+ Log.i(TAG, "User denies Headset Port existence");
+ recordHeasetPortFound(false);
+ getPassButton().setEnabled(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
}
}
}
@@ -146,10 +163,17 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_frequency_mic_activity);
mContext = this;
+
+ mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+ mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+ mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+ mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
mSpeakerReadyText = (TextView) findViewById(R.id.audio_frequency_mic_speakers_ready_status);
mSpeakersReady = (Button)findViewById(R.id.audio_frequency_mic_speakers_ready_btn);
mSpeakersReady.setOnClickListener(mBtnClickListener);
+ mSpeakersReady.setEnabled(false);
mTest1Button = (Button)findViewById(R.id.audio_frequency_mic_test1_btn);
mTest1Button.setOnClickListener(mBtnClickListener);
mTest1Result = (TextView)findViewById(R.id.audio_frequency_mic_results1_text);
@@ -644,6 +668,14 @@
Log.v(TAG, "Results Recorded");
}
+ private void recordHeasetPortFound(boolean found) {
+ getReportLog().addValue(
+ "User Reported Headset Port",
+ found ? 1.0 : 0,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ }
+
private void startRecording() {
synchronized (mRecordingLock) {
mIsRecording = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
similarity index 82%
copy from apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
copy to apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
index 93e0507..e253635 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputDeviceNotificationsActivity.java
@@ -16,7 +16,6 @@
package com.android.cts.verifier.audio;
-import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import android.content.Context;
@@ -34,10 +33,10 @@
import android.widget.TextView;
/**
- * Tests Audio Device Connection events by prompting the user to insert/remove a wired headset
- * and noting the presence (or absence) of notifictions.
+ * Tests Audio Device Connection events for output by prompting the user to insert/remove a
+ * wired headset (or microphone) and noting the presence (or absence) of notifications.
*/
-public class AudioDeviceNotificationsActivity extends PassFailButtons.Activity {
+public class AudioInputDeviceNotificationsActivity extends HeadsetHonorSystemActivity {
Context mContext;
TextView mConnectView;
@@ -62,6 +61,11 @@
}
@Override
+ protected void enableTestButtons(boolean enabled) {
+ // Nothing to do.
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_dev_notify);
@@ -71,6 +75,9 @@
mConnectView = (TextView)findViewById(R.id.audio_dev_notification_connect_msg);
mDisconnectView = (TextView)findViewById(R.id.audio_dev_notification_disconnect_msg);
+ ((TextView)findViewById(R.id.info_text)).setText(mContext.getResources().getString(
+ R.string.audio_in_devices_notification_instructions));
+
mClearMsgsBtn = (Button)findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn);
mClearMsgsBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -82,6 +89,9 @@
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
+ // "Honor System" buttons
+ super.setup();
+
setPassFailButtonClickListeners();
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
new file mode 100644
index 0000000..eefa9e4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -0,0 +1,120 @@
+/*
+ * 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.verifier.audio;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests AudioRecord (re)Routing messages.
+ */
+public class AudioInputRoutingNotificationsActivity extends HeadsetHonorSystemActivity {
+ private static final String TAG = "AudioInputRoutingNotificationsActivity";
+
+ Button recordBtn;
+ Button stopBtn;
+
+ Context mContext;
+
+ int mNumRecordNotifications = 0;
+
+ OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+ TrivialRecorder mAudioRecorder = new TrivialRecorder();
+
+ private class OnBtnClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.audio_routingnotification_recordBtn:
+ mAudioRecorder.start();
+ break;
+
+ case R.id.audio_routingnotification_recordStopBtn:
+ mAudioRecorder.stop();
+ break;
+ }
+ }
+ }
+
+ private class AudioRecordRoutingChangeListener implements AudioRecord.OnRoutingChangedListener {
+ public void onRoutingChanged(AudioRecord audioRecord) {
+ mNumRecordNotifications++;
+ TextView textView =
+ (TextView)findViewById(R.id.audio_routingnotification_audioRecord_change);
+ String msg = mContext.getResources().getString(
+ R.string.audio_routingnotification_recordRoutingMsg);
+ AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
+ CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+ int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+ textView.setText(msg + " - " +
+ deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+ " - " + mNumRecordNotifications);
+ }
+ }
+
+ protected void enableTestButtons(boolean enabled) {
+ recordBtn.setEnabled(enabled);
+ stopBtn.setEnabled(enabled);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.audio_input_routingnotifications_test);
+
+ Button btn;
+ recordBtn = (Button)findViewById(R.id.audio_routingnotification_recordBtn);
+ recordBtn.setOnClickListener(mBtnClickListener);
+ stopBtn = (Button)findViewById(R.id.audio_routingnotification_recordStopBtn);
+ stopBtn.setOnClickListener(mBtnClickListener);
+
+ mContext = this;
+
+ AudioRecord audioRecord = mAudioRecorder.getAudioRecord();
+ audioRecord.addOnRoutingChangedListener(
+ new AudioRecordRoutingChangeListener(), new Handler());
+
+ // "Honor System" buttons
+ super.setup();
+
+ setPassFailButtonClickListeners();
+ }
+
+ @Override
+ public void onBackPressed () {
+ mAudioRecorder.shutDown();
+ super.onBackPressed();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
index e603a69..fbec57a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackActivity.java
@@ -61,6 +61,9 @@
OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Context mContext;
+ Button mHeadsetPortYes;
+ Button mHeadsetPortNo;
+
Button mLoopbackPlugReady;
TextView mAudioLevelText;
SeekBar mAudioLevelSeekbar;
@@ -83,7 +86,20 @@
Log.i(TAG, "audio loopback test");
startAudioTest();
break;
-
+ case R.id.audio_general_headset_yes:
+ Log.i(TAG, "User confirms Headset Port existence");
+ mLoopbackPlugReady.setEnabled(true);
+ recordHeasetPortFound(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
+ case R.id.audio_general_headset_no:
+ Log.i(TAG, "User denies Headset Port existence");
+ recordHeasetPortFound(false);
+ getPassButton().setEnabled(true);
+ mHeadsetPortYes.setEnabled(false);
+ mHeadsetPortNo.setEnabled(false);
+ break;
}
}
}
@@ -95,8 +111,14 @@
mContext = this;
+ mHeadsetPortYes = (Button)findViewById(R.id.audio_general_headset_yes);
+ mHeadsetPortYes.setOnClickListener(mBtnClickListener);
+ mHeadsetPortNo = (Button)findViewById(R.id.audio_general_headset_no);
+ mHeadsetPortNo.setOnClickListener(mBtnClickListener);
+
mLoopbackPlugReady = (Button)findViewById(R.id.audio_loopback_plug_ready_btn);
mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+ mLoopbackPlugReady.setEnabled(false);
mLinearLayout = (LinearLayout)findViewById(R.id.audio_loopback_layout);
mAudioLevelText = (TextView)findViewById(R.id.audio_loopback_level_text);
mAudioLevelSeekbar = (SeekBar)findViewById(R.id.audio_loopback_level_seekbar);
@@ -135,7 +157,7 @@
setPassFailButtonClickListeners();
getPassButton().setEnabled(false);
- setInfoResources(R.string.sample_test, R.string.audio_loopback_info, -1);
+ setInfoResources(R.string.audio_loopback_test, R.string.audio_loopback_info, -1);
}
/**
@@ -304,4 +326,12 @@
Log.v(TAG,"Results Recorded");
}
+
+ private void recordHeasetPortFound(boolean found) {
+ getReportLog().addValue(
+ "User Reported Headset Port",
+ found ? 1.0 : 0,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
similarity index 82%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
index 93e0507..ad8ba68 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioDeviceNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputDeviceNotificationsActivity.java
@@ -16,7 +16,6 @@
package com.android.cts.verifier.audio;
-import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import android.content.Context;
@@ -34,10 +33,10 @@
import android.widget.TextView;
/**
- * Tests Audio Device Connection events by prompting the user to insert/remove a wired headset
- * and noting the presence (or absence) of notifictions.
+ * Tests Audio Device Connection events for output devices by prompting the user to
+ * insert/remove a wired headset and noting the presence (or absence) of notifications.
*/
-public class AudioDeviceNotificationsActivity extends PassFailButtons.Activity {
+public class AudioOutputDeviceNotificationsActivity extends HeadsetHonorSystemActivity {
Context mContext;
TextView mConnectView;
@@ -62,6 +61,11 @@
}
@Override
+ protected void enableTestButtons(boolean enabled) {
+ // Nothing to do.
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_dev_notify);
@@ -71,6 +75,9 @@
mConnectView = (TextView)findViewById(R.id.audio_dev_notification_connect_msg);
mDisconnectView = (TextView)findViewById(R.id.audio_dev_notification_disconnect_msg);
+ ((TextView)findViewById(R.id.info_text)).setText(mContext.getResources().getString(
+ R.string.audio_out_devices_notification_instructions));
+
mClearMsgsBtn = (Button)findViewById(R.id.audio_dev_notification_connect_clearmsgs_btn);
mClearMsgsBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -82,6 +89,9 @@
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(new TestAudioDeviceCallback(), null);
+ // "Honor System" buttons
+ super.setup();
+
setPassFailButtonClickListeners();
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
new file mode 100644
index 0000000..a6d8846
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -0,0 +1,120 @@
+/*
+ * 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.verifier.audio;
+
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests AudioTrack and AudioRecord (re)Routing messages.
+ */
+public class AudioOutputRoutingNotificationsActivity extends HeadsetHonorSystemActivity {
+ private static final String TAG = "AudioOutputRoutingNotificationsActivity";
+
+ Context mContext;
+
+ Button playBtn;
+ Button stopBtn;
+
+ private OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+ int mNumTrackNotifications = 0;
+
+ TrivialPlayer mAudioPlayer = new TrivialPlayer();
+
+ private class OnBtnClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.audio_routingnotification_playBtn:
+ mAudioPlayer.start();
+ break;
+
+ case R.id.audio_routingnotification_playStopBtn:
+ mAudioPlayer.stop();
+ break;
+ }
+ }
+ }
+
+ private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
+ public void onRoutingChanged(AudioTrack audioTrack) {
+ mNumTrackNotifications++;
+ TextView textView =
+ (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change);
+ String msg = mContext.getResources().getString(
+ R.string.audio_routingnotification_trackRoutingMsg);
+ AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
+ CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
+ int deviceType = routedDevice != null ? routedDevice.getType() : -1;
+ textView.setText(msg + " - " +
+ deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
+ " - " + mNumTrackNotifications);
+ }
+ }
+
+ @Override
+ protected void enableTestButtons(boolean enabled) {
+ playBtn.setEnabled(enabled);
+ stopBtn.setEnabled(enabled);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.audio_output_routingnotifications_test);
+
+ mContext = this;
+
+ playBtn = (Button)findViewById(R.id.audio_routingnotification_playBtn);
+ playBtn.setOnClickListener(mBtnClickListener);
+ stopBtn = (Button)findViewById(R.id.audio_routingnotification_playStopBtn);
+ stopBtn.setOnClickListener(mBtnClickListener);
+
+ AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
+ audioTrack.addOnRoutingChangedListener(
+ new AudioTrackRoutingChangeListener(), new Handler());
+
+ // "Honor System" buttons
+ super.setup();
+
+ setPassFailButtonClickListeners();
+ }
+
+ @Override
+ public void onBackPressed () {
+ mAudioPlayer.shutDown();
+ super.onBackPressed();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
deleted file mode 100644
index b6a4255..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioRoutingNotificationsActivity.java
+++ /dev/null
@@ -1,146 +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.verifier.audio;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.Context;
-
-import android.media.AudioDeviceCallback;
-import android.media.AudioDeviceInfo;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.AudioTrack;
-
-import android.os.Bundle;
-import android.os.Handler;
-
-import android.util.Log;
-
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import android.widget.Button;
-import android.widget.TextView;
-
-/**
- * Tests AudioTrack and AudioRecord (re)Routing messages.
- */
-public class AudioRoutingNotificationsActivity extends PassFailButtons.Activity {
- private static final String TAG = "AudioRoutingNotificationsActivity";
-
- Context mContext;
-
- OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
-
- int mNumTrackNotifications = 0;
- int mNumRecordNotifications = 0;
-
- TrivialPlayer mAudioPlayer = new TrivialPlayer();
- TrivialRecorder mAudioRecorder = new TrivialRecorder();
-
- private class OnBtnClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.audio_routingnotification_playBtn:
- Log.i(TAG, "audio_routingnotification_playBtn");
- mAudioPlayer.start();
- break;
-
- case R.id.audio_routingnotification_playStopBtn:
- Log.i(TAG, "audio_routingnotification_playStopBtn");
- mAudioPlayer.stop();
- break;
-
- case R.id.audio_routingnotification_recordBtn:
- break;
-
- case R.id.audio_routingnotification_recordStopBtn:
- break;
- }
- }
- }
-
- private class AudioTrackRoutingChangeListener implements AudioTrack.OnRoutingChangedListener {
- public void onRoutingChanged(AudioTrack audioTrack) {
- mNumTrackNotifications++;
- TextView textView =
- (TextView)findViewById(R.id.audio_routingnotification_audioTrack_change);
- String msg = mContext.getResources().getString(
- R.string.audio_routingnotification_trackRoutingMsg);
- AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
- CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
- int deviceType = routedDevice != null ? routedDevice.getType() : -1;
- textView.setText(msg + " - " +
- deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
- " - " + mNumTrackNotifications);
- }
- }
-
- private class AudioRecordRoutingChangeListener implements AudioRecord.OnRoutingChangedListener {
- public void onRoutingChanged(AudioRecord audioRecord) {
- mNumRecordNotifications++;
- TextView textView =
- (TextView)findViewById(R.id.audio_routingnotification_audioRecord_change);
- String msg = mContext.getResources().getString(
- R.string.audio_routingnotification_recordRoutingMsg);
- AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
- CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
- int deviceType = routedDevice != null ? routedDevice.getType() : -1;
- textView.setText(msg + " - " +
- deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
- " - " + mNumRecordNotifications);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.audio_routingnotifications_test);
-
- Button btn;
- btn = (Button)findViewById(R.id.audio_routingnotification_playBtn);
- btn.setOnClickListener(mBtnClickListener);
- btn = (Button)findViewById(R.id.audio_routingnotification_playStopBtn);
- btn.setOnClickListener(mBtnClickListener);
- btn = (Button)findViewById(R.id.audio_routingnotification_recordBtn);
- btn.setOnClickListener(mBtnClickListener);
- btn = (Button)findViewById(R.id.audio_routingnotification_recordStopBtn);
- btn.setOnClickListener(mBtnClickListener);
-
- mContext = this;
-
- AudioTrack audioTrack = mAudioPlayer.getAudioTrack();
- audioTrack.addOnRoutingChangedListener(
- new AudioTrackRoutingChangeListener(), new Handler());
-
- AudioRecord audioRecord = mAudioRecorder.getAudioRecord();
- audioRecord.addOnRoutingChangedListener(
- new AudioRecordRoutingChangeListener(), new Handler());
-
- setPassFailButtonClickListeners();
- }
-
- @Override
- public void onBackPressed () {
- mAudioPlayer.shutDown();
- mAudioRecorder.shutDown();
- super.onBackPressed();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java
new file mode 100644
index 0000000..a82b994
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HeadsetHonorSystemActivity.java
@@ -0,0 +1,83 @@
+/*
+ * 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.verifier.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import android.content.Context;
+
+import android.os.Bundle;
+import android.os.Handler;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+//import android.widget.TextView;
+
+abstract class HeadsetHonorSystemActivity extends PassFailButtons.Activity {
+ private static final String TAG = "HeadsetHonorSystemActivity";
+
+ private OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+ abstract protected void enableTestButtons(boolean enabled);
+
+ private void recordHeadsetPortFound(boolean found) {
+ getReportLog().addValue(
+ "User Reported Headset Port",
+ found ? 1.0 : 0,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ }
+
+ protected void setup() {
+ // The "Honor" system buttons
+ ((Button)findViewById(R.id.audio_general_headset_no)).
+ setOnClickListener(mBtnClickListener);
+ ((Button)findViewById(R.id.audio_general_headset_yes)).
+ setOnClickListener(mBtnClickListener);
+
+ enableTestButtons(false);
+ }
+
+ private class OnBtnClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.audio_general_headset_no:
+ Log.i(TAG, "User denies Headset Port existence");
+ enableTestButtons(false);
+ recordHeadsetPortFound(false);
+ break;
+
+ case R.id.audio_general_headset_yes:
+ Log.i(TAG, "User confirms Headset Port existence");
+ enableTestButtons(true);
+ recordHeadsetPortFound(true);
+ break;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 27f8c28..e3ff74b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -39,12 +39,14 @@
import android.media.Image;
import android.media.ImageReader;
import android.media.ImageWriter;
+import android.media.Image.Plane;
import android.net.Uri;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
+import android.os.SystemClock;
import android.os.Vibrator;
import android.util.Log;
import android.util.Rational;
@@ -56,6 +58,8 @@
import com.android.ex.camera2.blocking.BlockingStateCallback;
import com.android.ex.camera2.blocking.BlockingSessionCallback;
+import com.android.cts.verifier.camera.its.StatsImage;
+
import org.json.JSONArray;
import org.json.JSONObject;
@@ -70,6 +74,8 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.ArrayList;
@@ -154,6 +160,9 @@
private AtomicInteger mCountYuv = new AtomicInteger();
private AtomicInteger mCountCapRes = new AtomicInteger();
private boolean mCaptureRawIsDng;
+ private boolean mCaptureRawIsStats;
+ private int mCaptureStatsGridWidth;
+ private int mCaptureStatsGridHeight;
private CaptureResult mCaptureResults[] = null;
private volatile ConditionVariable mInterlock3A = new ConditionVariable(true);
@@ -404,7 +413,7 @@
continue;
}
if (b.hasArray()) {
- mOpenSocket.getOutputStream().write(b.array());
+ mOpenSocket.getOutputStream().write(b.array(), 0, b.capacity());
} else {
byte[] barray = new byte[b.capacity()];
b.get(barray);
@@ -665,7 +674,16 @@
jsonSurface.put("height", readers[i].getHeight());
int format = readers[i].getImageFormat();
if (format == ImageFormat.RAW_SENSOR) {
- jsonSurface.put("format", "raw");
+ if (mCaptureRawIsStats) {
+ jsonSurface.put("format", "rawStats");
+ jsonSurface.put("width", readers[i].getWidth()/mCaptureStatsGridWidth);
+ jsonSurface.put("height",
+ readers[i].getHeight()/mCaptureStatsGridHeight);
+ } else if (mCaptureRawIsDng) {
+ jsonSurface.put("format", "dng");
+ } else {
+ jsonSurface.put("format", "raw");
+ }
} else if (format == ImageFormat.RAW10) {
jsonSurface.put("format", "raw10");
} else if (format == ImageFormat.RAW12) {
@@ -1068,6 +1086,12 @@
outputFormats[i] = ImageFormat.RAW_SENSOR;
sizes = ItsUtils.getRaw16OutputSizes(mCameraCharacteristics);
mCaptureRawIsDng = true;
+ } else if ("rawStats".equals(sformat)) {
+ outputFormats[i] = ImageFormat.RAW_SENSOR;
+ sizes = ItsUtils.getRaw16OutputSizes(mCameraCharacteristics);
+ mCaptureRawIsStats = true;
+ mCaptureStatsGridWidth = surfaceObj.optInt("gridWidth");
+ mCaptureStatsGridHeight = surfaceObj.optInt("gridHeight");
} else {
throw new ItsException("Unsupported format: " + sformat);
}
@@ -1086,6 +1110,14 @@
if (height <= 0) {
height = ItsUtils.getMaxSize(sizes).getHeight();
}
+ if (mCaptureStatsGridWidth <= 0) {
+ mCaptureStatsGridWidth = width;
+ }
+ if (mCaptureStatsGridHeight <= 0) {
+ mCaptureStatsGridHeight = height;
+ }
+
+ // TODO: Crop to the active array in the stats image analysis.
outputSizes[i] = new Size(width, height);
}
@@ -1122,6 +1154,7 @@
mCountRaw12.set(0);
mCountCapRes.set(0);
mCaptureRawIsDng = false;
+ mCaptureRawIsStats = false;
mCaptureResults = new CaptureResult[requests.size()];
JSONArray jsonOutputSpecs = ItsUtils.getOutputSpecs(params);
@@ -1235,6 +1268,7 @@
mCountRaw12.set(0);
mCountCapRes.set(0);
mCaptureRawIsDng = false;
+ mCaptureRawIsStats = false;
try {
// Parse the JSON to get the list of capture requests.
@@ -1427,8 +1461,28 @@
int count = mCountRawOrDng.getAndIncrement();
if (! mCaptureRawIsDng) {
byte[] img = ItsUtils.getDataFromImage(capture);
- ByteBuffer buf = ByteBuffer.wrap(img);
- mSocketRunnableObj.sendResponseCaptureBuffer("rawImage", buf);
+ if (! mCaptureRawIsStats) {
+ ByteBuffer buf = ByteBuffer.wrap(img);
+ mSocketRunnableObj.sendResponseCaptureBuffer("rawImage", buf);
+ } else {
+ // Compute the requested stats on the raw frame, and return the results
+ // in a new "stats image".
+ long startTimeMs = SystemClock.elapsedRealtime();
+ int w = capture.getWidth();
+ int h = capture.getHeight();
+ int gw = mCaptureStatsGridWidth;
+ int gh = mCaptureStatsGridHeight;
+ float[] stats = StatsImage.computeStatsImage(img, w, h, gw, gh);
+ long endTimeMs = SystemClock.elapsedRealtime();
+ Log.e(TAG, "Raw stats computation takes " + (endTimeMs - startTimeMs) + " ms");
+
+ ByteBuffer bBuf = ByteBuffer.allocateDirect(stats.length * 4);
+ bBuf.order(ByteOrder.nativeOrder());
+ FloatBuffer fBuf = bBuf.asFloatBuffer();
+ fBuf.put(stats);
+ fBuf.position(0);
+ mSocketRunnableObj.sendResponseCaptureBuffer("rawStatsImage", bBuf);
+ }
} else {
// Wait until the corresponding capture result is ready, up to a timeout.
long t0 = android.os.SystemClock.elapsedRealtime();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java
new file mode 100644
index 0000000..037177c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/StatsImage.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.camera.its;
+
+import android.util.Log;
+
+public class StatsImage {
+
+ static {
+ try {
+ System.loadLibrary("ctsverifier_jni");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e("StatsImage", "Error loading cts verifier JNI library");
+ e.printStackTrace();
+ }
+ }
+
+ public native static float[] computeStatsImage(
+ byte[] img, int width, int height, int gridW, int gridH);
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 51e0a62..3c108da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -232,6 +232,7 @@
public static final Feature[] ALL_MNC_FEATURES = {
new Feature(PackageManager.FEATURE_MIDI, false),
+ new Feature(PackageManager.FEATURE_AUDIO_PRO, false),
};
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
new file mode 100644
index 0000000..073412d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
@@ -0,0 +1,381 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.KeyguardManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CountDownTimer;
+import android.provider.Settings;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.UserNotAuthenticatedException;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestResult;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * Test device credential-bound keys in work profile.
+ * Currently there are two types, one is keys bound to lockscreen passwords which can be configured
+ * to remain available within a certain timeout after the latest successful user authentication.
+ * The other is keys bound to fingerprint authentication which require explicit fingerprint
+ * authentication before they can be accessed.
+ */
+public class AuthenticationBoundKeyTestActivity extends DialogTestListActivity {
+
+ public static final String ACTION_AUTH_BOUND_KEY_TEST =
+ "com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST";
+
+ private static final int AUTHENTICATION_DURATION_SECONDS = 5;
+ private static final String LOCKSCREEN_KEY_NAME = "mp_lockscreen_key";
+ private static final String FINGERPRINT_KEY_NAME = "mp_fingerprint_key";
+ private static final byte[] SECRET_BYTE_ARRAY = new byte[] {1, 2, 3, 4, 5, 6};
+ private static final int CONFIRM_CREDENTIALS_REQUEST_CODE = 1;
+ private static final int FINGERPRINT_PERMISSION_REQUEST_CODE = 0;
+
+ private static final int LOCKSCREEN = 1;
+ private static final int FINGERPRINT = 2;
+
+ private static final String KEYSTORE_NAME = "AndroidKeyStore";
+ private static final String CIPHER_TRANSFORMATION = KeyProperties.KEY_ALGORITHM_AES + "/"
+ + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7;
+
+
+ private KeyguardManager mKeyguardManager;
+ private FingerprintManager mFingerprintManager;
+ private boolean mFingerprintSupported;
+
+ private DialogTestListItem mLockScreenBoundKeyTest;
+ private DialogTestListItem mFingerprintBoundKeyTest;
+
+ private Cipher mFingerprintCipher;
+
+ public AuthenticationBoundKeyTestActivity() {
+ super(R.layout.provisioning_byod,
+ R.string.provisioning_byod_auth_bound_key,
+ R.string.provisioning_byod_auth_bound_key_info,
+ R.string.provisioning_byod_auth_bound_key_instruction);
+ }
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
+ mFingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
+ mFingerprintSupported = mFingerprintManager != null
+ && mFingerprintManager.isHardwareDetected();
+ // Need to have valid mFingerprintSupported value before calling super.onCreate() because
+ // mFingerprintSupported is used in setupTests() which gets called by super.onCreate().
+ super.onCreate(savedInstanceState);
+
+ mPrepareTestButton.setText(R.string.provisioning_byod_auth_bound_key_set_up);
+ mPrepareTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
+ }
+ });
+ if (mFingerprintSupported) {
+ requestPermissions(new String[] {Manifest.permission.USE_FINGERPRINT},
+ FINGERPRINT_PERMISSION_REQUEST_CODE);
+ }
+ }
+
+ private class LockscreenCountDownTester extends CountDownTimer {
+
+ private Toast mToast;
+
+ public LockscreenCountDownTester() {
+ // Wait for AUTHENTICATION_DURATION_SECONDS so the key is evicted before the real test.
+ super(AUTHENTICATION_DURATION_SECONDS * 1000, 1000);
+ mToast = Toast.makeText(AuthenticationBoundKeyTestActivity.this, "", Toast.LENGTH_SHORT);
+ }
+
+ @Override
+ public void onFinish() {
+ mToast.cancel();
+ if (tryEncryptWithLockscreenKey()) {
+ showToast("Test failed. Key accessible without auth.");
+ setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ } else {
+ // Start the Confirm Credentials screen.
+ Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
+ if (intent != null) {
+ startActivityForResult(intent, CONFIRM_CREDENTIALS_REQUEST_CODE);
+ } else {
+ showToast("Test failed. No lockscreen password exists.");
+ setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ }
+ }
+ }
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ mToast.setText(String.format("Lockscreen challenge start in %d seconds..",
+ millisUntilFinished / 1000));
+ mToast.show();
+ }
+ }
+
+
+ @Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ mLockScreenBoundKeyTest = new DialogTestListItem(this,
+ R.string.provisioning_byod_lockscreen_bound_key,
+ "BYOD_LockScreenBoundKeyTest") {
+
+ @Override
+ public void performTest(DialogTestListActivity activity) {
+ if (checkPreconditions()) {
+ createKey(LOCKSCREEN);
+ new LockscreenCountDownTester().start();
+ }
+ }
+ };
+ adapter.add(mLockScreenBoundKeyTest);
+
+ if (mFingerprintSupported) {
+ mFingerprintBoundKeyTest = new DialogTestListItem(this,
+ R.string.provisioning_byod_fingerprint_bound_key,
+ "BYOD_FingerprintBoundKeyTest") {
+
+ @Override
+ public void performTest(DialogTestListActivity activity) {
+ if (checkPreconditions()) {
+ createKey(FINGERPRINT);
+ mFingerprintCipher = initFingerprintEncryptionCipher();
+ if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+ showToast("Test failed. Key accessible without auth.");
+ setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ } else {
+ new FingerprintAuthDialogFragment().show(getFragmentManager(),
+ "fingerprint_dialog");
+ }
+ }
+ }
+ };
+ adapter.add(mFingerprintBoundKeyTest);
+ }
+ }
+
+ private boolean checkPreconditions() {
+ if (!mKeyguardManager.isKeyguardSecure()) {
+ showToast("Please set a lockscreen password.");
+ return false;
+ } else if (mFingerprintSupported && !mFingerprintManager.hasEnrolledFingerprints()) {
+ showToast("Please enroll a fingerprint.");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private String getKeyName(int testType) {
+ return testType == LOCKSCREEN ? LOCKSCREEN_KEY_NAME : FINGERPRINT_KEY_NAME;
+ }
+ /**
+ * Creates a symmetric key in the Android Key Store which can only be used after the user has
+ * authenticated with device credentials.
+ */
+ private void createKey(int testType) {
+ try {
+ // Set the alias of the entry in Android KeyStore where the key will appear
+ // and the constrains (purposes) in the constructor of the Builder
+ KeyGenParameterSpec.Builder builder;
+ builder = new KeyGenParameterSpec.Builder(getKeyName(testType),
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setUserAuthenticationRequired(true)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
+ if (testType == LOCKSCREEN) {
+ // Require that the user unlocked the lockscreen in the last 5 seconds
+ builder.setUserAuthenticationValidityDurationSeconds(
+ AUTHENTICATION_DURATION_SECONDS);
+ }
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
+ keyGenerator.init(builder.build());
+ keyGenerator.generateKey();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException
+ | InvalidAlgorithmParameterException e) {
+ throw new RuntimeException("Failed to create a symmetric key", e);
+ }
+ }
+
+ private SecretKey loadSecretKey(int testType) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
+ keyStore.load(null);
+ return (SecretKey) keyStore.getKey(getKeyName(testType), null);
+ } catch (UnrecoverableKeyException | CertificateException |KeyStoreException | IOException
+ | NoSuchAlgorithmException e) {
+ throw new RuntimeException("Failed to load a symmetric key", e);
+ }
+ }
+
+ private boolean tryEncryptWithLockscreenKey() {
+ try {
+ // Try encrypting something, it will only work if the user authenticated within
+ // the last AUTHENTICATION_DURATION_SECONDS seconds.
+ Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+ cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(LOCKSCREEN));
+ cipher.doFinal(SECRET_BYTE_ARRAY);
+ return true;
+ } catch (UserNotAuthenticatedException e) {
+ // User is not authenticated, let's authenticate with device credentials.
+ return false;
+ } catch (KeyPermanentlyInvalidatedException e) {
+ // This happens if the lock screen has been disabled or reset after the key was
+ // generated.
+ createKey(LOCKSCREEN);
+ showToast("Set up lockscreen after test ran. Retry the test.");
+ return false;
+ } catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException
+ | NoSuchPaddingException | NoSuchAlgorithmException e) {
+ throw new RuntimeException("Encrypt with lockscreen-bound key failed", e);
+ }
+ }
+
+ private Cipher initFingerprintEncryptionCipher() {
+ try {
+ Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+ cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(FINGERPRINT));
+ return cipher;
+ } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
+ return null;
+ } catch (KeyPermanentlyInvalidatedException e) {
+ // This happens if the lock screen has been disabled or reset after the key was
+ // generated after the key was generated.
+ createKey(FINGERPRINT);
+ showToast("Set up lockscreen after test ran. Retry the test.");
+ return null;
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("Init cipher with fingerprint-bound key failed", e);
+ }
+ }
+
+ private boolean tryEncryptWithFingerprintKey(Cipher cipher) {
+
+ try {
+ cipher.doFinal(SECRET_BYTE_ARRAY);
+ return true;
+ } catch (IllegalBlockSizeException e) {
+ // Cannot encrypt, key is unavailable
+ return false;
+ } catch (BadPaddingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void handleActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case CONFIRM_CREDENTIALS_REQUEST_CODE:
+ if (resultCode == RESULT_OK) {
+ if (tryEncryptWithLockscreenKey()) {
+ setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+ } else {
+ showToast("Test failed. Key not accessible after auth");
+ setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ }
+ } else {
+ showToast("Lockscreen challenge canceled.");
+ setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ }
+ break;
+ default:
+ super.handleActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ private void showToast(String message) {
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+ }
+
+ public class FingerprintAuthDialogFragment extends DialogFragment {
+
+ private CancellationSignal mCancellationSignal;
+ private FingerprintManagerCallback mFingerprintManagerCallback;
+ private boolean mSelfCancelled;
+
+ class FingerprintManagerCallback extends FingerprintManager.AuthenticationCallback {
+ @Override
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ if (!mSelfCancelled) {
+ showToast(errString.toString());
+ }
+ }
+
+ @Override
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ showToast(helpString.toString());
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ showToast(getString(R.string.sec_fp_auth_failed));
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+ if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+ showToast("Test passed.");
+ setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+ } else {
+ showToast("Test failed. Key not accessible after auth");
+ setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+ }
+ FingerprintAuthDialogFragment.this.dismiss();
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mCancellationSignal.cancel();
+ mSelfCancelled = true;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mCancellationSignal = new CancellationSignal();
+ mSelfCancelled = false;
+ mFingerprintManagerCallback = new FingerprintManagerCallback();
+ mFingerprintManager.authenticate(new FingerprintManager.CryptoObject(mFingerprintCipher),
+ mCancellationSignal, 0, mFingerprintManagerCallback, null);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setMessage(R.string.sec_fp_dialog_message);
+ return builder.create();
+ }
+
+ }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 0200a4f..b129665 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -19,6 +19,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -59,7 +60,9 @@
private DialogTestListItem mProfileAccountVisibleTest;
private DialogTestListItem mDeviceAdminVisibleTest;
private DialogTestListItem mWorkAppVisibleTest;
- private DialogTestListItem mCrossProfileIntentFiltersTest;
+ private DialogTestListItem mCrossProfileIntentFiltersTestFromPersonal;
+ private DialogTestListItem mCrossProfileIntentFiltersTestFromWork;
+ private DialogTestListItem mAppLinkingTest;
private DialogTestListItem mDisableNonMarketTest;
private DialogTestListItem mEnableNonMarketTest;
private DialogTestListItem mWorkNotificationBadgedTest;
@@ -78,6 +81,7 @@
private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
private TestListItem mKeyguardDisabledFeaturesTest;
private DialogTestListItem mDisableNfcBeamTest;
+ private TestListItem mAuthenticationBoundKeyTest;
public ByodFlowTestActivity() {
super(R.layout.provisioning_byod,
@@ -264,20 +268,39 @@
R.string.provisioning_byod_print_settings_instruction,
new Intent(Settings.ACTION_PRINT_SETTINGS));
- Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+ Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
+ intent.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, false);
Intent chooser = Intent.createChooser(intent,
getResources().getString(R.string.provisioning_cross_profile_chooser));
- mCrossProfileIntentFiltersTest = new DialogTestListItem(this,
- R.string.provisioning_byod_cross_profile,
- "BYOD_CrossProfileIntentFiltersTest",
- R.string.provisioning_byod_cross_profile_instruction,
+ mCrossProfileIntentFiltersTestFromPersonal = new DialogTestListItem(this,
+ R.string.provisioning_byod_cross_profile_from_personal,
+ "BYOD_CrossProfileIntentFiltersTestFromPersonal",
+ R.string.provisioning_byod_cross_profile_from_personal_instruction,
chooser);
+ mCrossProfileIntentFiltersTestFromWork = new DialogTestListItem(this,
+ R.string.provisioning_byod_cross_profile_from_work,
+ "BYOD_CrossProfileIntentFiltersTestFromWork",
+ R.string.provisioning_byod_cross_profile_from_work_instruction,
+ new Intent(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG));
+
+ mAppLinkingTest = new DialogTestListItem(this,
+ R.string.provisioning_app_linking,
+ "BYOD_AppLinking",
+ R.string.provisioning_byod_app_linking_instruction,
+ new Intent(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG));
+
mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
R.string.provisioning_byod_keyguard_disabled_features,
KeyguardDisabledFeaturesActivity.class.getName(),
new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
+ mAuthenticationBoundKeyTest = TestListItem.newTest(this,
+ R.string.provisioning_byod_auth_bound_key,
+ AuthenticationBoundKeyTestActivity.class.getName(),
+ new Intent(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST),
+ null);
+
// Test for checking if the required intent filters are set during managed provisioning.
mIntentFiltersTest = new DialogTestListItem(this,
R.string.provisioning_byod_cross_profile_intent_filters,
@@ -287,7 +310,7 @@
checkIntentFilters();
}
};
-
+
Intent permissionCheckIntent = new Intent(
PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
mPermissionLockdownTest = new DialogTestListItem(this,
@@ -314,12 +337,15 @@
adapter.add(mDataUsageSettingsVisibleTest);
adapter.add(mPrintSettingsVisibleTest);
- adapter.add(mCrossProfileIntentFiltersTest);
+ adapter.add(mCrossProfileIntentFiltersTestFromPersonal);
+ adapter.add(mCrossProfileIntentFiltersTestFromWork);
+ adapter.add(mAppLinkingTest);
adapter.add(mDisableNonMarketTest);
adapter.add(mEnableNonMarketTest);
adapter.add(mIntentFiltersTest);
adapter.add(mPermissionLockdownTest);
adapter.add(mKeyguardDisabledFeaturesTest);
+ adapter.add(mAuthenticationBoundKeyTest);
if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
// Capture image intent can be resolved in primary profile, so test.
@@ -495,7 +521,8 @@
ByodHelperActivity.class.getName(),
WorkNotificationTestActivity.class.getName(),
WorkStatusTestActivity.class.getName(),
- PermissionLockdownTestActivity.ACTIVITY_ALIAS
+ PermissionLockdownTestActivity.ACTIVITY_ALIAS,
+ AuthenticationBoundKeyTestActivity.class.getName()
};
for (String component : components) {
getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
@@ -503,4 +530,5 @@
PackageManager.DONT_KILL_APP);
}
}
+
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 3d7d42d..9ea5061 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -27,6 +27,7 @@
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.UserManager;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.v4.content.FileProvider;
@@ -84,6 +85,18 @@
public static final String ACTION_CHECK_INTENT_FILTERS =
"com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS";
+ // Primary -> managed intent: will send a cross profile intent and check if the user sees an
+ // intent picker dialog and can open the apps.
+ public static final String ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG =
+ "com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG";
+
+ // Primary -> managed intent: will send an app link intent and check if the user sees a
+ // dialog and can open the apps. This test is extremely similar to
+ // ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG, but the intent used is a web intent, and there is
+ // some behavior which is specific to web intents.
+ public static final String ACTION_TEST_APP_LINKING_DIALOG =
+ "com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG";
+
public static final int RESULT_FAILED = RESULT_FIRST_USER;
private static final int REQUEST_INSTALL_PACKAGE = 1;
@@ -211,6 +224,16 @@
startActivity(testNfcBeamIntent);
finish();
return;
+ } else if (action.equals(ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG)) {
+ sendIntentInsideChooser(new Intent(
+ CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL));
+ } else if (action.equals(ACTION_TEST_APP_LINKING_DIALOG)) {
+ mDevicePolicyManager.addUserRestriction(
+ DeviceAdminTestReceiver.getReceiverComponentName(),
+ UserManager.ALLOW_PARENT_PROFILE_APP_LINKING);
+ Intent toSend = new Intent(Intent.ACTION_VIEW);
+ toSend.setData(Uri.parse("http://com.android.cts.verifier"));
+ sendIntentInsideChooser(toSend);
}
// This activity has no UI and is only used to respond to CtsVerifier in the primary side.
finish();
@@ -346,6 +369,13 @@
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
}
+ private void sendIntentInsideChooser(Intent toSend) {
+ toSend.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, true);
+ Intent chooser = Intent.createChooser(toSend,
+ getResources().getString(R.string.provisioning_cross_profile_chooser));
+ startActivity(chooser);
+ }
+
@Override
public void onDialogClose() {
finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
index b3f126b..15f5bc8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
@@ -31,10 +31,14 @@
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.VideoView;
-
+import android.view.Display;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.content.ContentResolver;
import com.android.cts.verifier.R;
import java.io.IOException;
+import java.io.InputStream;
/**
* This dialog shows/plays an image, video or audio uri.
@@ -46,6 +50,7 @@
private static final String KEY_IMAGE_URI = "image";
private static final String KEY_AUDIO_URI = "audio";
+ private Bitmap scaled = null;
/**
* Get a dialogFragment showing an image.
*/
@@ -79,6 +84,16 @@
return dialog;
}
+ private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ if(reqWidth <= 0 || reqHeight <= 0) {
+ return 1;
+ }
+ return Math.max(height/reqHeight, width/reqWidth) + 1;
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Dialog dialog = new Dialog(getActivity());
@@ -114,11 +129,36 @@
} else if (arguments.containsKey(KEY_IMAGE_URI)) {
// Show image UI.
dialog.setTitle(getString(R.string.provisioning_byod_verify_image_title));
-
- Uri uri = (Uri) getArguments().getParcelable(KEY_IMAGE_URI);
+ Uri uri = (Uri)getArguments().getParcelable(KEY_IMAGE_URI);
ImageView imageView = (ImageView) dialog.findViewById(R.id.imageView);
imageView.setVisibility(View.VISIBLE);
- imageView.setImageURI(uri);
+
+ try{
+ InputStream input = getActivity().getContentResolver().openInputStream(uri);
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(input, null, options);
+ //scale the picture
+ Display display = getActivity().getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int reqWidth = size.x;
+ int reqHeight = size.y;
+ options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+ options.inJustDecodeBounds = false;
+ input.close();
+ input = getActivity().getContentResolver().openInputStream(uri);
+ scaled = BitmapFactory.decodeStream(input, null, options);
+ input.close();
+ imageView.setImageBitmap(scaled);
+ }catch(IOException e){
+ Log.e(TAG, "Cannot get image.", e);
+ Toast.makeText(getActivity(),R.string.provisioning_byod_capture_image_error,
+ Toast.LENGTH_SHORT).show();
+ getActivity().finish();
+ }
+
} else if (arguments.containsKey(KEY_AUDIO_URI)) {
// Show audio playback UI.
dialog.setTitle(getString(R.string.provisioning_byod_verify_audio_title));
@@ -161,6 +201,13 @@
((DialogCallback) getActivity()).onDialogClose();
}
+ @Override
+ public void onDestroyView() {
+ if(scaled!=null){
+ scaled.recycle();
+ }
+ super.onDestroyView();
+ }
public interface DialogCallback {
public abstract void onDialogClose();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
index 6c38e12..3f316f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
@@ -35,7 +35,12 @@
*/
public class CrossProfileTestActivity extends Activity {
// Intent for app in both profiles
- public static final String ACTION_CROSS_PROFILE = "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE";
+ public static final String ACTION_CROSS_PROFILE_TO_PERSONAL =
+ "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL";
+ public static final String ACTION_CROSS_PROFILE_TO_WORK =
+ "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK";
+ public static final String EXTRA_STARTED_FROM_WORK
+ = "com.android.cts.verifier.managedprovisioning.STARTED_FROM_WORK";
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -45,9 +50,15 @@
// Check if we are running in the work or personal side, by testing if currently we are the
// profile owner or not.
- textView.setText(isProfileOwner() ? R.string.provisioning_byod_cross_profile_app_work
- : R.string.provisioning_byod_cross_profile_app_personal);
-
+ boolean inWorkProfile = isProfileOwner();
+ boolean startedFromWork = getIntent().getBooleanExtra(EXTRA_STARTED_FROM_WORK, false);
+ if (inWorkProfile && !startedFromWork) {
+ textView.setText(R.string.provisioning_byod_cross_profile_app_work);
+ } else if (!inWorkProfile && startedFromWork) {
+ textView.setText(R.string.provisioning_byod_cross_profile_app_personal);
+ } else { // started from the same side we're currently running in
+ textView.setText(R.string.provisioning_byod_cross_profile_app_ctsverifier);
+ }
findViewById(R.id.button_finish).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 008091b..ed6b5eb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -64,7 +64,9 @@
filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
filter.addAction(ByodHelperActivity.ACTION_TEST_NFC_BEAM);
- filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+ filter.addAction(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG);
+ filter.addAction(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG);
+ filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
@@ -72,12 +74,14 @@
filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
filter.addAction(
PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
+ filter.addAction(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
// Work -> primary direction
filter = new IntentFilter();
filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+ filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index 7dc99c0..eef6299 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -30,6 +30,7 @@
import android.net.Uri;
import android.nfc.cardemulation.CardEmulation;
import android.os.Bundle;
+import android.os.Environment;
import android.os.UserHandle;
import android.provider.AlarmClock;
import android.provider.CalendarContract.Events;
@@ -39,6 +40,7 @@
import android.util.Log;
import android.widget.Toast;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
@@ -51,132 +53,83 @@
private static final String TAG = "IntentFiltersTestHelper";
// These are the intents which can be forwarded to the managed profile.
- private static final Intent[] forwardedIntentsFromPrimary = new Intent[] {
- new Intent(Intent.ACTION_SEND).setType("*/*"),
- new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
- };
+ private static final ArrayList<Intent> forwardedIntentsFromPrimary =
+ new ArrayList<>(Arrays.asList(
+ new Intent(Intent.ACTION_SEND).setType("*/*"),
+ new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")
+ ));
// These are the intents which can be forwarded to the primary profile.
- private static final Intent[] forwardedIntentsFromManaged = new Intent[] {
- new Intent(AlarmClock.ACTION_SET_ALARM),
- new Intent(AlarmClock.ACTION_SET_TIMER),
- new Intent(AlarmClock.ACTION_SHOW_ALARMS),
- new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
- new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
- new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
- new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
- new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
- new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
- new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
- new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
- new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
- new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
- new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS),
- new Intent(Settings.ACTION_APN_SETTINGS),
- new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
- new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
- new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
- new Intent(Settings.ACTION_DATE_SETTINGS),
- new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
- new Intent(Settings.ACTION_DISPLAY_SETTINGS),
- new Intent(Settings.ACTION_DREAM_SETTINGS),
- new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
- new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS),
- new Intent(Settings.ACTION_LOCALE_SETTINGS),
- new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
- new Intent(Settings.ACTION_NFC_SETTINGS),
- new Intent(Settings.ACTION_NFCSHARING_SETTINGS),
- new Intent(Settings.ACTION_PRIVACY_SETTINGS),
- new Intent(Settings.ACTION_SETTINGS),
- new Intent(Settings.ACTION_SOUND_SETTINGS),
- new Intent(Settings.ACTION_WIRELESS_SETTINGS),
- new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
- new Intent("android.net.vpn.SETTINGS"),
- new Intent(CardEmulation.ACTION_CHANGE_DEFAULT),
- new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
- new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
- new Intent(Settings.ACTION_HOME_SETTINGS),
- new Intent("android.settings.LICENSE"),
- new Intent("android.settings.NOTIFICATION_SETTINGS"),
- new Intent(Settings.ACTION_SHOW_REGULATORY_INFO),
- new Intent("android.settings.USER_SETTINGS"),
- new Intent("android.settings.ZEN_MODE_SETTINGS"),
- new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
- new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
- new Intent("com.android.settings.TTS_SETTINGS"),
- new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
- new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
- new Intent("android.intent.action.CALL_EMERGENCY").setData(Uri.parse("tel:123")),
- new Intent("android.intent.action.CALL_PRIVILEGED").setData(Uri.parse("tel:123")),
- new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
- new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS),
- new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS),
- new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
- new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
- new Intent(Settings.ACTION_SYNC_SETTINGS),
- new Intent(Settings.ACTION_ADD_ACCOUNT),
- new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
- Intent.CATEGORY_OPENABLE),
- new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
- Intent.CATEGORY_OPENABLE),
- new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
- new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
- new Intent(Settings.ACTION_APPLICATION_SETTINGS),
- new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS"),
- new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
- new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
- new Intent(Settings.ACTION_WIFI_SETTINGS),
- new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
- };
+ private static final ArrayList<Intent> forwardedIntentsFromManaged =
+ new ArrayList<>(Arrays.asList(
+ new Intent(AlarmClock.ACTION_SET_ALARM),
+ new Intent(AlarmClock.ACTION_SET_TIMER),
+ new Intent(AlarmClock.ACTION_SHOW_ALARMS),
+ new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
+ new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
+ new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
+ new Intent(Settings.ACTION_DATE_SETTINGS),
+ new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
+ new Intent(Settings.ACTION_DISPLAY_SETTINGS),
+ new Intent(Settings.ACTION_LOCALE_SETTINGS),
+ new Intent(Settings.ACTION_PRIVACY_SETTINGS),
+ new Intent(Settings.ACTION_SETTINGS),
+ new Intent(Settings.ACTION_WIRELESS_SETTINGS),
+ new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
+ new Intent("android.net.vpn.SETTINGS"),
+ new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
+ new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
+ new Intent("android.settings.LICENSE"),
+ new Intent("android.settings.NOTIFICATION_SETTINGS"),
+ new Intent("android.settings.USER_SETTINGS"),
+ new Intent("android.settings.ZEN_MODE_SETTINGS"),
+ new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
+ new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
+ new Intent("com.android.settings.TTS_SETTINGS"),
+ new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
+ new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
+ new Intent(Settings.ACTION_SYNC_SETTINGS),
+ new Intent(Settings.ACTION_ADD_ACCOUNT),
+ new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory(
+ Intent.CATEGORY_OPENABLE),
+ new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory(
+ Intent.CATEGORY_OPENABLE),
+ new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS),
+ new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS),
+ new Intent(Settings.ACTION_APPLICATION_SETTINGS)
+ ));
// These are the intents which cannot be forwarded to the primary profile.
- private static final Intent[] notForwardedIntentsFromManaged = new Intent[] {
- new Intent(Intent.ACTION_INSERT).setData(
- Uri.parse("content://browser/bookmarks")),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("http://www.example.com")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_SENDTO).setData(
- Uri.parse("mailto:user@example.com")),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("mailto:user@example.com")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("geo:0,0?q=BuckinghamPalace")),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
- new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
- new Intent(Intent.ACTION_VIEW).setData(
- Uri.parse("market://details?id=com.android.chrome")).addCategory(
- Intent.CATEGORY_BROWSABLE),
- new Intent(Intent.ACTION_WEB_SEARCH),
- new Intent(Settings.ACTION_SEARCH_SETTINGS),
- new Intent(Settings.ACTION_PRINT_SETTINGS),
- new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
- new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
- Uri.parse("package:com.android.chrome")),
- new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"),
- new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
- new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL),
- new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
- };
+ private static final ArrayList<Intent> notForwardedIntentsFromManaged =
+ new ArrayList<>(Arrays.asList(
+ new Intent(Intent.ACTION_INSERT).setData(
+ Uri.parse("content://browser/bookmarks")),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("http://www.example.com")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_SENDTO).setData(
+ Uri.parse("mailto:user@example.com")),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("mailto:user@example.com")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("geo:0,0?q=BuckinghamPalace")),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("http://example.com/oceans.mp4")).setType("video/mp4"),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("http://www.example.com/horse.mp3")).setType("audio/*"),
+ new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("market://details?id=com.android.chrome")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_WEB_SEARCH),
+ new Intent(Settings.ACTION_SEARCH_SETTINGS),
+ new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE),
+ new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+ Uri.parse("package:com.android.chrome")),
+ new Intent(Intent.ACTION_INSERT).setData(Events.CONTENT_URI),
+ new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
+ ));
// This flag specifies we are dealing with intents fired from the primary profile.
public static final int FLAG_INTENTS_FROM_PRIMARY = 1;
@@ -187,6 +140,124 @@
IntentFiltersTestHelper(Context context) {
mContext = context;
+
+ addIntentsThatDependOnDeviceFeatures();
+ }
+
+ private void addIntentsThatDependOnDeviceFeatures() {
+ PackageManager pm = mContext.getPackageManager();
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
+ new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
+ new Intent("android.intent.action.CALL_EMERGENCY").setData(
+ Uri.parse("tel:123")),
+ new Intent("android.intent.action.CALL_PRIVILEGED").setData(
+ Uri.parse("tel:123")),
+ new Intent(Intent.ACTION_VIEW).setData(Uri.parse("tel:123")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS),
+ new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS),
+ new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("sms:07700900100")),
+ new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("smsto:07700900100")),
+ new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mms:07700900100")),
+ new Intent(Intent.ACTION_SENDTO).setData(Uri.parse("mmsto:07700900100")),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("sms:07700900100?body=Hello%20world")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("smsto:07700900100?body=Hello%20world")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("mms:07700900100?body=Hello%20world")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Intent.ACTION_VIEW).setData(
+ Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
+ Intent.CATEGORY_BROWSABLE),
+ new Intent(Settings.ACTION_APN_SETTINGS)));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(Settings.ACTION_NFC_SETTINGS),
+ new Intent(Settings.ACTION_NFCSHARING_SETTINGS),
+ new Intent(Settings.ACTION_NFC_PAYMENT_SETTINGS)));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(CardEmulation.ACTION_CHANGE_DEFAULT));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
+ new Intent(MediaStore.ACTION_VIDEO_CAPTURE),
+ new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA),
+ new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA),
+ new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE),
+ new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)));
+ }
+
+ final String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(Settings.ACTION_WIFI_IP_SETTINGS),
+ new Intent(Settings.ACTION_WIFI_SETTINGS)));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION),
+ new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_LOCATION)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(Settings.ACTION_SOUND_SETTINGS),
+ new Intent("android.settings.ACTION_OTHER_SOUND_SETTINGS")));
+ notForwardedIntentsFromManaged.add(
+ new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_HOME_SCREEN)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_HOME_SETTINGS));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)) {
+ forwardedIntentsFromManaged.addAll(Arrays.asList(
+ new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS),
+ new Intent(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS)));
+ notForwardedIntentsFromManaged.add(
+ new Intent("android.settings.SHOW_INPUT_METHOD_PICKER"));
+ }
+
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_DREAM_SETTINGS));
+ }
+
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ forwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS));
+ }
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+ notForwardedIntentsFromManaged.add(
+ new Intent(Settings.ACTION_PRINT_SETTINGS));
+ }
}
public boolean checkCrossProfileIntentFilters(int flag) {
@@ -298,7 +369,7 @@
* @return {@code null} if all the intents are correctly handled
* otherwise, the first intent in the list which is not handled correctly.
*/
- private Intent checkForIntentsNotHandled(Intent[] intentList,
+ private Intent checkForIntentsNotHandled(ArrayList<Intent> intentList,
ActivityInfo expectedForwarderActivityInfo, boolean canResolve) {
for (Intent intent : intentList) {
if (canForwarderActivityHandleIntent(intent,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
index 8e72ebb..0728fb5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/screenpinning/ScreenPinningTestActivity.java
@@ -31,6 +31,8 @@
private static final String TAG = "ScreenPinningTestActivity";
private static final String KEY_CURRENT_TEST = "keyCurrentTest";
+ private static final long TASK_MODE_CHECK_DELAY = 200;
+ private static final int MAX_TASK_MODE_CHECK_COUNT = 5;
private Test[] mTests;
private int mTestIndex;
@@ -203,10 +205,18 @@
return;
}
stopLockTask();
- if (!mActivityManager.isInLockTaskMode()) {
- succeed();
- } else {
- error(R.string.error_screen_pinning_couldnt_exit);
+ for (int retry = MAX_TASK_MODE_CHECK_COUNT; retry > 0; retry--) {
+ try {
+ Thread.sleep(TASK_MODE_CHECK_DELAY);
+ } catch (InterruptedException e) {
+ }
+ Log.d(TAG, "Check unpin ... " + retry);
+ if (!mActivityManager.isInLockTaskMode()) {
+ succeed();
+ break;
+ } else if (retry == 1) {
+ error(R.string.error_screen_pinning_couldnt_exit);
+ }
}
};
};
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
index 70899c6..bca7a66 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
@@ -89,6 +89,22 @@
if (requestCode == FINGERPRINT_PERMISSION_REQUEST_CODE && state[0] == PackageManager.PERMISSION_GRANTED) {
mFingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
mKeyguardManager = (KeyguardManager) getSystemService(KeyguardManager.class);
+ Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
+
+ if (!mKeyguardManager.isKeyguardSecure()) {
+ // Show a message that the user hasn't set up a lock screen.
+ showToast( "Secure lock screen hasn't been set up.\n"
+ + "Go to 'Settings -> Security -> Screen lock' to set up a lock screen");
+ startTestButton.setEnabled(false);
+ return;
+ } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
+ showToast("No fingerprints enrolled.\n"
+ + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint");
+ startTestButton.setEnabled(false);
+ return;
+ }
+
+ createKey();
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
@@ -107,7 +123,6 @@
throw new RuntimeException("Failed to init Cipher", e);
}
- Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
startTestButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -117,21 +132,7 @@
showAuthenticationScreen();
}
}
-
});
-
- if (!mKeyguardManager.isKeyguardSecure()) {
- // Show a message that the user hasn't set up a lock screen.
- showToast( "Secure lock screen hasn't been set up.\n"
- + "Go to 'Settings -> Security -> Screen lock' to set up a lock screen");
- startTestButton.setEnabled(false);
- } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
- showToast("No fingerprints enrolled.\n"
- + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint");
- startTestButton.setEnabled(false);
- } else {
- createKey();
- }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
index a5b58f6..fa89b71 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
@@ -23,9 +23,9 @@
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.ViewGroup;
import java.io.IOException;
-import java.util.List;
/** Camera preview class */
public class RVCVCameraPreview extends SurfaceView implements SurfaceHolder.Callback {
@@ -34,15 +34,16 @@
private SurfaceHolder mHolder;
private Camera mCamera;
+ private float mAspect;
+ private int mRotation;
/**
* Constructor
* @param context Activity context
- * @param camera Camera object to be previewed
*/
- public RVCVCameraPreview(Context context, Camera camera) {
+ public RVCVCameraPreview(Context context) {
super(context);
- mCamera = camera;
+ mCamera = null;
initSurface();
}
@@ -55,8 +56,10 @@
super(context, attrs);
}
- public void init(Camera camera) {
+ public void init(Camera camera, float aspectRatio, int rotation) {
this.mCamera = camera;
+ mAspect = aspectRatio;
+ mRotation = rotation;
initSurface();
}
@@ -86,6 +89,20 @@
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
+ int v_height = getHeight();
+ int v_width = getWidth();
+ ViewGroup.LayoutParams layout = getLayoutParams();
+ if ( (float)v_height/v_width >
+ mAspect) {
+ layout.height = (int)(v_width * mAspect);
+ layout.width = v_width;
+ }else {
+ layout.width = (int)(v_height / mAspect);
+ layout.height = v_height;
+ }
+ Log.d(TAG, String.format("Layout (%d, %d) -> (%d, %d)", v_width, v_height,
+ layout.width, layout.height));
+ setLayoutParams(layout);
} catch (IOException e) {
if (LOCAL_LOGD) Log.d(TAG, "Error when starting camera preview: " + e.getMessage());
}
@@ -111,8 +128,7 @@
// stop preview before making changes
mCamera.stopPreview();
- // the activity using this view is locked to this orientation, so hard code is fine
- mCamera.setDisplayOrientation(90);
+ mCamera.setDisplayOrientation(mRotation);
//do the same as if it is created again
surfaceCreated(holder);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
index f90b27c..be5ec52 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
@@ -46,6 +46,7 @@
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.List;
// ----------------------------------------------------------------------
@@ -67,7 +68,7 @@
private VideoRecorder mVideoRecorder;
private RVSensorLogger mRVSensorLogger;
private CoverageManager mCoverManager;
- private CameraPreviewer mPreviewer;
+ private CameraContext mCameraContext;
public static final int AXIS_NONE = 0;
public static final int AXIS_ALL = SensorManager.AXIS_X +
@@ -99,7 +100,7 @@
super.onPause();
mController.quit();
- mPreviewer.end();
+ mCameraContext.end();
endSoundPool();
}
@@ -128,8 +129,8 @@
*
*/
private void init() {
- mPreviewer = new CameraPreviewer();
- mPreviewer.init();
+ mCameraContext = new CameraContext();
+ mCameraContext.init();
mCoverManager = new CoverageManager();
mIndicatorView.setDataProvider(
@@ -140,7 +141,7 @@
initSoundPool();
mRVSensorLogger = new RVSensorLogger(this);
- mVideoRecorder = new VideoRecorder(mPreviewer.getCamera());
+ mVideoRecorder = new VideoRecorder(mCameraContext.getCamera(), mCameraContext.getProfile());
if (LOG_RAW_SENSORS) {
mRawSensorLogger = new RawSensorLogger(mRecordDir);
@@ -173,7 +174,8 @@
// X and Y
final String axisName = "YXZ";
- message("Manipulate the device in " + axisName.charAt(axis-1) + " axis (as illustrated) about the pattern.");
+ message("Manipulate the device in " + axisName.charAt(axis - 1) +
+ " axis (as illustrated) about the pattern.");
}
/**
@@ -250,20 +252,28 @@
* Start the sensor recording
*/
public void startRecordSensor() {
- mRVSensorLogger.init();
- if (LOG_RAW_SENSORS) {
- mRawSensorLogger.init();
- }
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mRVSensorLogger.init();
+ if (LOG_RAW_SENSORS) {
+ mRawSensorLogger.init();
+ }
+ }
+ });
}
/**
* Stop the sensor recording
*/
public void stopRecordSensor() {
- mRVSensorLogger.end();
- if (LOG_RAW_SENSORS) {
- mRawSensorLogger.end();
- }
+ runOnUiThread(new Runnable() {
+ public void run() {
+ mRVSensorLogger.end();
+ if (LOG_RAW_SENSORS) {
+ mRawSensorLogger.end();
+ }
+ }
+ });
}
/**
@@ -365,20 +375,93 @@
/**
* Camera preview control class
*/
- class CameraPreviewer {
+ class CameraContext {
private Camera mCamera;
+ private CamcorderProfile mProfile;
+ private Camera.CameraInfo mCameraInfo;
- CameraPreviewer() {
+ private int [] mPreferredProfiles = {
+ CamcorderProfile.QUALITY_480P, // smaller -> faster
+ CamcorderProfile.QUALITY_720P,
+ CamcorderProfile.QUALITY_1080P,
+ CamcorderProfile.QUALITY_HIGH // existence guaranteed
+ };
+
+ CameraContext() {
try {
- mCamera = Camera.open(); // attempt to get a default Camera instance
+ mCamera = Camera.open(); // attempt to get a default Camera instance (0)
+ mProfile = null;
+ if (mCamera != null) {
+ mCameraInfo = new Camera.CameraInfo();
+ Camera.getCameraInfo(0, mCameraInfo);
+ setupCamera();
+ }
}
- catch (Exception e) {
+ catch (Exception e){
// Camera is not available (in use or does not exist)
Log.e(TAG, "Cannot obtain Camera!");
}
}
/**
+ * Find a preferred camera profile and set preview and picture size property accordingly.
+ */
+ void setupCamera() {
+ CamcorderProfile profile = null;
+ Camera.Parameters param = mCamera.getParameters();
+ List<Camera.Size> pre_sz = param.getSupportedPreviewSizes();
+ List<Camera.Size> pic_sz = param.getSupportedPictureSizes();
+
+ for (int i : mPreferredProfiles) {
+ if (CamcorderProfile.hasProfile(i)) {
+ profile = CamcorderProfile.get(i);
+
+ int valid = 0;
+ for (Camera.Size j : pre_sz) {
+ if (j.width == profile.videoFrameWidth &&
+ j.height == profile.videoFrameHeight) {
+ ++valid;
+ break;
+ }
+ }
+ for (Camera.Size j : pic_sz) {
+ if (j.width == profile.videoFrameWidth &&
+ j.height == profile.videoFrameHeight) {
+ ++valid;
+ break;
+ }
+ }
+ if (valid == 2) {
+ param.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
+ param.setPictureSize(profile.videoFrameWidth, profile.videoFrameHeight);
+ mCamera.setParameters(param);
+ break;
+ } else {
+ profile = null;
+ }
+ }
+ }
+ if (profile != null) {
+ float fovW = param.getHorizontalViewAngle();
+ float fovH = param.getVerticalViewAngle();
+ writeVideoMetaInfo(profile.videoFrameWidth, profile.videoFrameHeight,
+ profile.videoFrameRate, fovW, fovH);
+ } else {
+ Log.e(TAG, "Cannot find a proper video profile");
+ }
+ mProfile = profile;
+
+ }
+
+
+ /**
+ * Get sensor information of the camera being used
+ */
+ public Camera.CameraInfo getCameraInfo() {
+ return mCameraInfo;
+ }
+
+ /**
* Get the camera to be previewed
* @return Reference to Camera used
*/
@@ -387,12 +470,20 @@
}
/**
+ * Get the camera profile to be used
+ * @return Reference to Camera profile
+ */
+ public CamcorderProfile getProfile() {
+ return mProfile;
+ }
+
+ /**
* Setup the camera
*/
public void init() {
if (mCamera != null) {
double alpha = mCamera.getParameters().getHorizontalViewAngle()*Math.PI/180.0;
- int width = 1920;
+ int width = mProfile.videoFrameWidth;
double fx = width/2/Math.tan(alpha/2.0);
if (LOCAL_LOGV) Log.v(TAG, "View angle="
@@ -400,7 +491,9 @@
RVCVCameraPreview cameraPreview =
(RVCVCameraPreview) findViewById(R.id.cam_preview);
- cameraPreview.init(mCamera);
+ cameraPreview.init(mCamera,
+ (float)mProfile.videoFrameWidth/mProfile.videoFrameHeight,
+ mCameraInfo.orientation);
} else {
message("Cannot open camera!");
finish();
@@ -466,26 +559,22 @@
class VideoRecorder
{
private MediaRecorder mRecorder;
+ private CamcorderProfile mProfile;
private Camera mCamera;
private boolean mRunning = false;
- private int [] mPreferredProfiles = { CamcorderProfile.QUALITY_480P, // smaller -> faster
- CamcorderProfile.QUALITY_720P,
- CamcorderProfile.QUALITY_1080P,
- CamcorderProfile.QUALITY_HIGH // existence guaranteed
- };
-
-
- VideoRecorder(Camera camera) {
+ VideoRecorder(Camera camera, CamcorderProfile profile){
mCamera = camera;
+ mProfile = profile;
}
/**
* Initialize and start recording
*/
public void init() {
- float fovW = mCamera.getParameters().getHorizontalViewAngle();
- float fovH = mCamera.getParameters().getVerticalViewAngle();
+ if (mCamera == null || mProfile ==null){
+ return;
+ }
mRecorder = new MediaRecorder();
mCamera.unlock();
@@ -494,17 +583,7 @@
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
- CamcorderProfile profile = null;
- for (int i: mPreferredProfiles) {
- if (CamcorderProfile.hasProfile(i)) {
- profile = CamcorderProfile.get(i);
- mRecorder.setProfile(profile);
- break;
- }
- }
-
- writeVideoMetaInfo(profile.videoFrameWidth, profile.videoFrameHeight,
- profile.videoFrameRate, fovW, fovH);
+ mRecorder.setProfile(mProfile);
try {
mRecorder.setOutputFile(getVideoRecFilePath());
@@ -689,8 +768,20 @@
*/
public void init() {
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
+ if (mSensorManager == null) {
+ Log.e(TAG,"SensorManager is null!");
+ }
mRVSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
- mSensorManager.registerListener(this, mRVSensor, SENSOR_RATE);
+ if (mRVSensor != null) {
+ if (LOCAL_LOGV) Log.v(TAG, "Got RV Sensor");
+ }else {
+ Log.e(TAG, "Did not get RV sensor");
+ }
+ if(mSensorManager.registerListener(this, mRVSensor, SENSOR_RATE)) {
+ if (LOCAL_LOGV) Log.v(TAG,"Register listener successfull");
+ } else {
+ Log.e(TAG,"Register listener failed");
+ }
try {
mLogWriter= new OutputStreamWriter(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
index 9afd1a9..3dc7270 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
@@ -15,12 +15,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Debug;
import android.os.Environment;
+import android.os.PowerManager;
import android.util.JsonWriter;
import android.util.Log;
@@ -777,14 +777,16 @@
VideoMetaInfo meta = new VideoMetaInfo(new File(mPath, "videometa.json"));
int decimation = 1;
+ boolean use_timestamp = true;
+ // roughly determine if decimation is necessary
if (meta.fps > DECIMATION_FPS_TARGET) {
decimation = (int)(meta.fps / DECIMATION_FPS_TARGET);
meta.fps /=decimation;
}
VideoDecoderForOpenCV videoDecoder = new VideoDecoderForOpenCV(
- new File(mPath, "video.mp4"), decimation); // every 3 frame process 1 frame
+ new File(mPath, "video.mp4"), decimation);
Mat frame;
@@ -820,12 +822,17 @@
}
long startTime = System.nanoTime();
+ long [] ts = new long[1];
- while ((frame = videoDecoder.getFrame()) !=null) {
+ while ((frame = videoDecoder.getFrame(ts)) !=null) {
if (LOCAL_LOGV) {
Log.v(TAG, "got a frame " + i);
}
+ if (use_timestamp && ts[0] == -1) {
+ use_timestamp = false;
+ }
+
// has to be in front, as there are cases where execution
// will skip the later part of this while
i++;
@@ -873,8 +880,16 @@
// if error is reasonable, add it into the results
if (error < REPROJECTION_THREASHOLD) {
double [] rv = new double[3];
+ double timestamp;
+
rvec.get(0,0, rv);
- recs.add(new AttitudeRec((double) i / meta.fps, rodr2rpy(rv)));
+ if (use_timestamp) {
+ timestamp = (double)ts[0] / 1e6;
+ } else {
+ timestamp = (double) i / meta.fps;
+ }
+ if (LOCAL_LOGV) Log.v(TAG, String.format("Added frame %d ts = %f", i, timestamp));
+ recs.add(new AttitudeRec(timestamp, rodr2rpy(rv)));
}
if (OUTPUT_DEBUG_IMAGE) {
@@ -906,6 +921,8 @@
* One issue right now is that the glReadPixels is quite slow .. around 6.5ms for a 720p frame
*/
private class VideoDecoderForOpenCV implements Runnable {
+ static final String TAG = "VideoDecoderForOpenCV";
+
private MediaExtractor extractor=null;
private MediaCodec decoder=null;
private CtsMediaOutputSurface surface=null;
@@ -1031,7 +1048,7 @@
}
if (decoder == null) {
- Log.e("VideoDecoderForOpenCV", "Can't find video info!");
+ Log.e(TAG, "Can't find video info!");
return;
}
valid = true;
@@ -1060,6 +1077,7 @@
long timeoutUs = 10000;
int iframe = 0;
+ long frameTimestamp = 0;
while (!Thread.interrupted()) {
if (!isEOS) {
@@ -1076,8 +1094,12 @@
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
- decoder.queueInputBuffer(inIndex, 0, sampleSize,
- extractor.getSampleTime(), 0);
+ frameTimestamp = extractor.getSampleTime();
+ decoder.queueInputBuffer(inIndex, 0, sampleSize, frameTimestamp, 0);
+ if (LOCAL_LOGD) {
+ Log.d(TAG, String.format("Frame %d sample time %f s",
+ iframe, (double)frameTimestamp/1e6));
+ }
extractor.advance();
}
}
@@ -1088,19 +1110,19 @@
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
if (LOCAL_LOGD) {
- Log.d("VideoDecoderForOpenCV", "INFO_OUTPUT_BUFFERS_CHANGED");
+ Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
}
outputBuffers = decoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
outFormat = decoder.getOutputFormat();
if (LOCAL_LOGD) {
- Log.d("VideoDecoderForOpenCV", "New format " + outFormat);
+ Log.d(TAG, "New format " + outFormat);
}
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
if (LOCAL_LOGD) {
- Log.d("VideoDecoderForOpenCV", "dequeueOutputBuffer timed out!");
+ Log.d(TAG, "dequeueOutputBuffer timed out!");
}
break;
default:
@@ -1118,12 +1140,12 @@
if (doRender) {
surface.awaitNewImage();
surface.drawImage();
- if (LOCAL_LOGD) {
- Log.d("VideoDecoderForOpenCV", "Finish drawing a frame!");
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Finish drawing a frame!");
}
if ((iframe++ % mDecimation) == 0) {
//Send the frame for processing
- mMatBuffer.put();
+ mMatBuffer.put(frameTimestamp);
}
}
break;
@@ -1149,8 +1171,8 @@
* Get next valid frame
* @return Frame in OpenCV mat
*/
- public Mat getFrame() {
- return mMatBuffer.get();
+ public Mat getFrame(long ts[]) {
+ return mMatBuffer.get(ts);
}
/**
@@ -1168,6 +1190,7 @@
private Mat mat;
private byte[] bytes;
private ByteBuffer buf;
+ private long timestamp;
private boolean full;
private int mWidth, mHeight;
@@ -1180,6 +1203,7 @@
mat = new Mat(height, width, CvType.CV_8UC4); //RGBA
buf = ByteBuffer.allocateDirect(width*height*4);
bytes = new byte[width*height*4];
+ timestamp = -1;
mValid = true;
full = false;
@@ -1190,7 +1214,7 @@
notifyAll();
}
- public synchronized Mat get() {
+ public synchronized Mat get(long ts[]) {
if (!mValid) return null;
while (full == false) {
@@ -1204,9 +1228,11 @@
mat.put(0,0, bytes);
full = false;
notifyAll();
+ ts[0] = timestamp;
return mat;
}
- public synchronized void put() {
+
+ public synchronized void put(long ts) {
while (full) {
try {
wait();
@@ -1219,6 +1245,7 @@
buf.get(bytes);
buf.rewind();
+ timestamp = ts;
full = true;
notifyAll();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
index 9a74a0e..35c4d56 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
@@ -16,9 +16,10 @@
package com.android.cts.verifier.sensors;
-
+import android.content.Context;
import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
import android.os.Bundle;
+import android.os.PowerManager;
import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
import com.android.cts.verifier.sensors.helpers.OpenCVLibrary;
@@ -82,7 +83,7 @@
while(retry-->0) {
try {
- Thread.sleep(100);
+ Thread.sleep(250);
} catch (InterruptedException e) {
//
}
@@ -146,7 +147,15 @@
// Analysis of recorded video and sensor data using RVCXAnalyzer
RVCVXCheckAnalyzer analyzer = new RVCVXCheckAnalyzer(mRecPath);
+
+ // acquire a partial wake lock just in case CPU fall asleep
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "RVCVXCheckAnalyzer");
+
+ wl.acquire();
mReport = analyzer.processDataSet();
+ wl.release();
playSound();
vibrate(500);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index 6dbf8cc..2dfc7c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -287,7 +287,9 @@
@Override
protected void activityCleanUp() {
- mScreenManipulator.turnScreenOff();
+ if (mScreenManipulator != null) {
+ mScreenManipulator.turnScreenOff();
+ }
LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
new file mode 100644
index 0000000..43f293a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
@@ -0,0 +1,113 @@
+/*
+ * 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.verifier.tv;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Tests for verifying TV app behavior for TV app-link.
+ */
+public class AppLinkTestActivity extends TvAppVerifierActivity implements View.OnClickListener {
+ private static final long TIMEOUT_MS = 5l * 60l * 1000l; // 5 mins.
+
+ private boolean mSelectAppLinkItemPassed;
+ private View mSelectAppLinkItem;
+ private View mVerifyAppLinkIntentItem;
+ private View mVerifyAppLinkCardItem;
+
+ Runnable mSelectAppLinkFailCallback;
+
+ @Override
+ public void onClick(View v) {
+ final View postTarget = getPostTarget();
+
+ if (containsButton(mSelectAppLinkItem, v)) {
+ Intent tvAppIntent = null;
+ String[] projection = { TvContract.Channels._ID };
+ try (Cursor cursor = getContentResolver().query(
+ TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
+ projection, null, null, null)) {
+ if (cursor != null && cursor.moveToNext()) {
+ tvAppIntent = new Intent(Intent.ACTION_VIEW,
+ TvContract.buildChannelUri(cursor.getLong(0)));
+ }
+ }
+ if (tvAppIntent == null) {
+ Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ mSelectAppLinkFailCallback = new Runnable() {
+ @Override
+ public void run() {
+ mSelectAppLinkItemPassed = false;
+ setPassState(mSelectAppLinkItem, false);
+ setPassState(mVerifyAppLinkIntentItem, false);
+ }
+ };
+ postTarget.postDelayed(mSelectAppLinkFailCallback, TIMEOUT_MS);
+ mSelectAppLinkItemPassed = true;
+ setPassState(mSelectAppLinkItem, true);
+
+ startActivity(tvAppIntent);
+ } else if (containsButton(mVerifyAppLinkCardItem, v)) {
+ setPassState(mVerifyAppLinkCardItem, true);
+ getPassButton().setEnabled(true);
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ if (mSelectAppLinkItemPassed
+ && TextUtils.equals(MockTvInputSetupActivity.APP_LINK_TEST_VALUE,
+ intent.getStringExtra(MockTvInputSetupActivity.APP_LINK_TEST_KEY))) {
+ getPostTarget().removeCallbacks(mSelectAppLinkFailCallback);
+ setPassState(mVerifyAppLinkIntentItem, true);
+ setButtonEnabled(mVerifyAppLinkCardItem, true);
+ }
+ }
+
+ @Override
+ protected void createTestItems() {
+ mSelectAppLinkItem = createUserItem(R.string.tv_app_link_test_select_app_link,
+ R.string.tv_launch_tv_app, this);
+ setButtonEnabled(mSelectAppLinkItem, true);
+ mVerifyAppLinkIntentItem = createAutoItem(
+ R.string.tv_app_link_test_verify_link_clicked);
+ mVerifyAppLinkCardItem = createUserItem(R.string.tv_input_link_test_verify_link_interface,
+ android.R.string.yes, this);
+ TextView instructions = (TextView) mVerifyAppLinkCardItem.findViewById(R.id.instructions);
+ Drawable image = getDrawable(R.drawable.app_link_img);
+ image.setBounds(0, 0, 317, 241);
+ instructions.setCompoundDrawablePadding(10);
+ instructions.setCompoundDrawables(image, null, null, null);
+ }
+
+ @Override
+ protected void setInfoResources() {
+ setInfoResources(R.string.tv_app_link_test, R.string.tv_app_link_test_info, -1);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
index c05b753..43ed7da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
@@ -17,9 +17,12 @@
package com.android.cts.verifier.tv;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.ContentUris;
import android.content.ContentValues;
+import android.content.Intent;
import android.database.Cursor;
+import android.graphics.Color;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Programs;
import android.media.tv.TvInputInfo;
@@ -28,6 +31,8 @@
import android.util.Pair;
import android.view.View;
+import com.android.cts.verifier.R;
+
import java.util.ArrayList;
public class MockTvInputSetupActivity extends Activity {
@@ -38,6 +43,10 @@
/* package-private */ static final String PROGRAM_TITLE = "Dummy Program";
/* package-private */ static final String PROGRAM_DESCRIPTION = "Dummy Program Description";
+
+ /* package-private */ static final String APP_LINK_TEST_KEY = "app_link_test_key";
+ /* package-private */ static final String APP_LINK_TEST_VALUE = "app_link_test_value";
+ private static final String APP_LINK_TEXT = "Cts App-Link Text";
private static final long PROGRAM_LENGTH_MILLIS = 60 * 60 * 1000;
private static final int PROGRAM_COUNT = 24;
@@ -69,6 +78,18 @@
values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId);
values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER);
values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME);
+ values.put(TvContract.Channels.COLUMN_APP_LINK_TEXT, APP_LINK_TEXT);
+ values.put(TvContract.Channels.COLUMN_APP_LINK_COLOR, Color.RED);
+ values.put(TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
+ "android.resource://" + getPackageName() + "/" + R.drawable.icon);
+ values.put(TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+ "android.resource://" + getPackageName() + "/" + R.raw.sns_texture);
+ Intent appLinkIntentUri = new Intent(this, AppLinkTestActivity.class);
+ appLinkIntentUri.putExtra(APP_LINK_TEST_KEY, APP_LINK_TEST_VALUE);
+ appLinkIntentUri.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+ values.put(TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
+ appLinkIntentUri.toUri(Intent.URI_INTENT_SCHEME));
+
Uri channelUri = getContentResolver().insert(uri, values);
// If the channel's ID happens to be zero, we add another and delete the one.
if (ContentUris.parseId(channelUri) == 0) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index 12e9652..acab18e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -35,8 +35,6 @@
public abstract class TvAppVerifierActivity extends PassFailButtons.Activity {
private static final String TAG = "TvAppVerifierActivity";
- private static final long TIMEOUT_MS = 5l * 60l * 1000l; // 5 mins.
-
private LayoutInflater mInflater;
private ViewGroup mItemList;
private View mPostTarget;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index 06f4f6f..e8e2cee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -25,8 +25,6 @@
import com.android.cts.verifier.R;
-import java.util.List;
-
/**
* Tests for verifying TV app behavior for third-party TV input apps.
*/
@@ -131,7 +129,7 @@
mGoToEpgItem = createUserItem(R.string.tv_input_discover_test_go_to_epg,
R.string.tv_launch_epg, this);
mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
- R.string.tv_input_discover_test_yes, this);
+ android.R.string.yes, this);
}
@Override
diff --git a/apps/cts-usb-accessory/Android.mk b/apps/cts-usb-accessory/Android.mk
index 8d18da3..f3a7ebd 100644
--- a/apps/cts-usb-accessory/Android.mk
+++ b/apps/cts-usb-accessory/Android.mk
@@ -33,6 +33,7 @@
LOCAL_STATIC_LIBRARIES := libusbhost libcutils
LOCAL_LDLIBS += -lpthread
LOCAL_CFLAGS := -g -O0
+LOCAL_CXX_STL := none
include $(BUILD_HOST_EXECUTABLE)
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
index 8fbae26..650875c 100644
--- a/build/test_deqp_package.mk
+++ b/build/test_deqp_package.mk
@@ -18,15 +18,14 @@
CTS_DEQP_CONFIG_PATH := $(call my-dir)
-cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
-$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml
-$(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
-$(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
-$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
-$(cts_library_xml): external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
- $(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
+cts_library_xmls:=$(foreach xml_file, $(call find-files-in-subdirs, external/deqp/android/cts/master, 'com.drawelements.deqp.$(DEQP_API).*xml', .), $(CTS_TESTCASES_OUT)/$(xml_file))
+$(cts_library_xmls) : PRIVATE_API := $(DEQP_API)
+$(cts_library_xmls) : PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
+$(cts_library_xmls) : PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
+$(cts_library_xmls) : PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
+$(cts_library_xmls) : $(CTS_TESTCASES_OUT)/%.xml: external/deqp/android/cts/master/%.xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+ $(hide) echo Generating test description $@
$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-
# Query build ABIs by routing a dummy test list through xml generator and parse result
$(hide) $(eval supported_abi_attr := $(shell $(CTS_XML_GENERATOR) -t dummyTest \
-n dummyName \
@@ -36,8 +35,7 @@
-a $(CTS_TARGET_ARCH) \
< $(PRIVATE_DUMMY_CASELIST) \
| grep --only-matching -e " abis=\"[^\"]*\""))
-
# Patch xml caselist with supported abi
$(hide) $(SED_EXTENDED) -e 's:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $(supported_abi_attr)\4>:' \
- < $(MUSTPASS_XML_FILE) \
+ < $< \
> $@
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
index f3af0bc..2f80911 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/DeviceInfoInstrument.java
@@ -25,19 +25,37 @@
import android.text.TextUtils;
import android.util.Log;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* An instrumentation that runs all activities that extends DeviceInfoActivity.
*/
public class DeviceInfoInstrument extends Instrumentation {
private static final String LOG_TAG = "ExtendedDeviceInfo";
- private static final int DEVICE_INFO_ACTIVITY_REQUEST = 1;
+ private static final String COLLECTOR = "collector";
+ // List of collectors to run. If null or empty, all collectors will run.
+ private Set<String> mCollectorSet = new HashSet<String>();
+
+ // Results sent to the caller when this istrumentation completes.
private Bundle mBundle = new Bundle();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ String collectorList = savedInstanceState.getString(COLLECTOR);
+ if (!TextUtils.isEmpty(collectorList)) {
+ for (String collector : TextUtils.split(collectorList, ",")) {
+ if (!TextUtils.isEmpty(collector)) {
+ mCollectorSet.add(collector);
+ }
+ }
+ }
+ }
start();
}
@@ -47,13 +65,8 @@
Context context = getContext();
ActivityInfo[] activities = context.getPackageManager().getPackageInfo(
context.getPackageName(), PackageManager.GET_ACTIVITIES).activities;
-
for (ActivityInfo activityInfo : activities) {
- Class cls = Class.forName(activityInfo.name);
- if (cls != DeviceInfoActivity.class &&
- DeviceInfoActivity.class.isAssignableFrom(cls)) {
- runActivity(activityInfo.name);
- }
+ runActivity(activityInfo.name);
}
} catch (Exception e) {
Log.e(LOG_TAG, "Exception occurred while running activities.", e);
@@ -65,9 +78,40 @@
}
/**
+ * Returns true if the activity meets the criteria to run; otherwise, false.
+ */
+ private boolean isActivityRunnable(Class activityClass) {
+ // Don't run the base DeviceInfoActivity class.
+ if (DeviceInfoActivity.class == activityClass) {
+ return false;
+ }
+ // Don't run anything that doesn't extends DeviceInfoActivity.
+ if (!DeviceInfoActivity.class.isAssignableFrom(activityClass)) {
+ return false;
+ }
+ // Only run activity if mCollectorSet is empty or contains it.
+ if (mCollectorSet != null && mCollectorSet.size() > 0) {
+ return mCollectorSet.contains(activityClass.getName());
+ }
+ // Run anything that makes it here.
+ return true;
+ }
+
+ /**
* Runs a device info activity and return the file path where the results are written to.
*/
private void runActivity(String activityName) throws Exception {
+ Class activityClass = null;
+ try {
+ activityClass = Class.forName(activityName);
+ } catch (ClassNotFoundException e) {
+ return;
+ }
+
+ if (activityClass == null || !isActivityRunnable(activityClass)) {
+ return;
+ }
+
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(this.getContext(), activityName);
@@ -76,7 +120,7 @@
waitForIdleSync();
activity.waitForActivityToFinish();
- String className = Class.forName(activityName).getSimpleName();
+ String className = activityClass.getSimpleName();
String errorMessage = activity.getErrorMessage();
if (TextUtils.isEmpty(errorMessage)) {
mBundle.putString(className, activity.getResultFilePath());
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
index f6e7c57..decf6dd 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
@@ -68,6 +68,8 @@
public static final String BUILD_SERIAL = "build_serial";
public static final String BUILD_VERSION_RELEASE = "build_version_release";
public static final String BUILD_VERSION_SDK = "build_version_sdk";
+ public static final String BUILD_VERSION_BASE_OS = "build_version_base_os";
+ public static final String BUILD_VERSION_SECURITY_PATH = "build_version_security_patch";
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -93,5 +95,7 @@
addResult(BUILD_SERIAL, Build.SERIAL);
addResult(BUILD_VERSION_RELEASE, Build.VERSION.RELEASE);
addResult(BUILD_VERSION_SDK, Build.VERSION.SDK);
+ addResult(BUILD_VERSION_BASE_OS, Build.VERSION.BASE_OS);
+ addResult(BUILD_VERSION_SECURITY_PATH, Build.VERSION.SECURITY_PATCH);
}
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
index 70414ca..2ae2e10 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
@@ -294,7 +294,7 @@
private LocalVolumeInfo getAdoptionVolume() throws Exception {
String[] lines = null;
int attempt = 0;
- while (attempt++ < 5) {
+ while (attempt++ < 15) {
lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
for (String line : lines) {
final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
diff --git a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
index a86f7f0..c460300 100644
--- a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -19,7 +19,7 @@
A simple app with a tracing section to test that apps tracing signals are
emitted by atrace.
-->
- <application>
+ <application android:debuggable="true"> <!-- Debuggable to enable tracing -->
<activity android:name=".AtraceTestAppActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index c8a2d8e..760723e 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -209,7 +209,7 @@
// capture a launch of the app with async tracing
// content traced by 'view' tag tested below, 'sched' used to ensure tgid printed
- String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view sched"; // TODO: zipping
+ String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view"; // TODO: zipping
getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
getDevice().executeShellCommand("atrace --async_start " + atraceArgs);
getDevice().executeShellCommand("am start " + TEST_PKG);
@@ -228,13 +228,15 @@
String traceData = atraceOutput.substring(dataStart + MARKER.length());
FtraceEntryCallback callback = new FtraceEntryCallback() {
- private int matches = 0;
- private int nextSectionIndex = 0;
- private int appPid = -1;
+ private int userSpaceMatches = 0;
+ private int beginMatches = 0;
+ private int nextSectionIndex = -1;
+ private int appTid = -1;
- // list of tags expected to be seen on app launch, in order.
+
+ private final String initialSection = "traceable-app-test-section";
+ // list of tags expected to be seen on app launch, in order, after the initial.
private final String[] requiredSectionList = {
- "traceable-app-test-section",
"inflate",
"Choreographer#doFrame",
"traversal",
@@ -252,34 +254,41 @@
return;
}
- matches++;
assertNotNull(truncatedThreadName);
assertTrue(tid > 0);
- if (TEST_PKG.endsWith(truncatedThreadName)) {
- matches++;
+ userSpaceMatches++;
- if (pid >= 0) {
- // verify pid, if present
- if (appPid == -1) {
- appPid = pid;
- } else {
- assertEquals(appPid, pid);
- }
- }
+ if (details == null || !details.startsWith("B|")) {
+ // not a begin event
+ return;
+ }
+ beginMatches++;
- if (nextSectionIndex < requiredSectionList.length
- && details != null
- && details.startsWith("B|")
- && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
- nextSectionIndex++;
- }
+ if (details.endsWith("|" + initialSection)) {
+ // initial section observed, start looking for others in order
+ assertEquals(nextSectionIndex, -1);
+ nextSectionIndex = 0;
+ appTid = tid;
+ return;
+ }
+
+ if (nextSectionIndex >= 0
+ && tid == appTid
+ && nextSectionIndex < requiredSectionList.length
+ && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
+ // found next required section in sequence
+ nextSectionIndex++;
}
}
@Override
public void onFinished() {
assertTrue("Unable to parse any userspace sections from atrace output",
- matches != 0);
+ userSpaceMatches != 0);
+ assertTrue("Unable to parse any section begin events from atrace output",
+ beginMatches != 0);
+ assertTrue("Unable to parse initial userspace sections from test app",
+ nextSectionIndex >= 0);
assertEquals("Didn't see required list of traced sections, in order",
requiredSectionList.length, nextSectionIndex);
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
index 6e520c3..fe07bcb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
@@ -71,6 +71,13 @@
android:resource="@xml/authenticator" />
</service>
+ <activity android:name=".UserRestrictionActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
new file mode 100644
index 0000000..fed1a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionActivity.java
@@ -0,0 +1,81 @@
+/*
+ * 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.deviceandprofileowner;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.Log;
+
+/**
+ * Simple activity that adds or clears a user restriction depending on the value of the extras.
+ */
+public class UserRestrictionActivity extends Activity {
+
+ private static final String TAG = UserRestrictionActivity.class.getName();
+
+ private static final String EXTRA_RESTRICTION_KEY = "extra-restriction-key";
+ private static final String EXTRA_COMMAND = "extra-command";
+
+ private static final String ADD_COMMAND = "add-restriction";
+ private static final String CLEAR_COMMAND = "clear-restriction";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ handleIntent(getIntent());
+ }
+
+ // Overriding this method in case another intent is sent to this activity before finish()
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // Calling finish() here because doing it in onCreate(), onStart() or onResume() makes
+ // "adb shell am start" timeout if using the -W option.
+ finish();
+ }
+
+ private void handleIntent(Intent intent) {
+ DevicePolicyManager dpm = (DevicePolicyManager)
+ getSystemService(Context.DEVICE_POLICY_SERVICE);
+ String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
+ String command = intent.getStringExtra(EXTRA_COMMAND);
+ Log.i(TAG, "Command: \"" + command + "\". Restriction: \"" + restrictionKey + "\"");
+
+ if (ADD_COMMAND.equals(command)) {
+ dpm.addUserRestriction(BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+ Log.i(TAG, "Added user restriction " + restrictionKey
+ + " for user " + Process.myUserHandle());
+ } else if (CLEAR_COMMAND.equals(command)) {
+ dpm.clearUserRestriction(
+ BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
+ Log.i(TAG, "Cleared user restriction " + restrictionKey
+ + " for user " + Process.myUserHandle());
+ } else {
+ Log.e(TAG, "Invalid command: " + command);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
index 9127dab..51c575c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CaCertManagementTest.java
@@ -15,69 +15,143 @@
*/
package com.android.cts.deviceowner;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
-import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
-
import java.io.ByteArrayInputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
+import java.util.Arrays;
import java.util.List;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import static com.android.cts.deviceowner.FakeKeys.FAKE_DSA_1;
+import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
+
public class CaCertManagementTest extends BaseDeviceOwnerTest {
+ /**
+ * Test: device admins should be able to list all installed certs.
+ *
+ * <p>The list of certificates must never be {@code null}.
+ */
public void testCanRetrieveListOfInstalledCaCerts() {
List<byte[]> caCerts = mDevicePolicyManager.getInstalledCaCerts(getWho());
assertNotNull(caCerts);
}
+ /**
+ * Test: a valid cert should be installable and also removable.
+ */
public void testCanInstallAndUninstallACaCert()
- throws CertificateException {
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ throws CertificateException, GeneralSecurityException {
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
- assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertInstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
}
- public void testUninstallationIsSelective() throws CertificateException {
+ /**
+ * Test: removing one certificate must not remove any others.
+ */
+ public void testUninstallationIsSelective()
+ throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_DSA_1.caCertificate);
- assertTrue(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertInstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
+
mDevicePolicyManager.uninstallCaCert(getWho(), FAKE_RSA_1.caCertificate);
}
- public void testCanUninstallAllUserCaCerts() throws CertificateException {
+ /**
+ * Test: uninstallAllUserCaCerts should be equivalent to calling uninstallCaCert on every
+ * supplementary installed certificate.
+ */
+ public void testCanUninstallAllUserCaCerts()
+ throws CertificateException, GeneralSecurityException {
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_RSA_1.caCertificate));
assertTrue(mDevicePolicyManager.installCaCert(getWho(), FAKE_DSA_1.caCertificate));
+
mDevicePolicyManager.uninstallAllUserCaCerts(getWho());
- assertFalse(hasCaCertInstalled(FAKE_RSA_1.caCertificate));
- assertFalse(hasCaCertInstalled(FAKE_DSA_1.caCertificate));
+ assertUninstalled(FAKE_RSA_1.caCertificate);
+ assertUninstalled(FAKE_DSA_1.caCertificate);
}
- private boolean hasCaCertInstalled(byte [] caCert) throws CertificateException {
- boolean result = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert);
- assertEquals(result, containsCertificate(
- mDevicePolicyManager.getInstalledCaCerts(getWho()), caCert));
- return result;
+ private void assertInstalled(byte[] caBytes)
+ throws CertificateException, GeneralSecurityException {
+ Certificate caCert = readCertificate(caBytes);
+ assertTrue(isCaCertInstalledAndTrusted(caCert));
}
- private static boolean containsCertificate(List<byte[]> certificates, byte [] toMatch)
- throws CertificateException {
- Certificate certificateToMatch = readCertificate(toMatch);
- for (byte[] certBuffer : certificates) {
- Certificate cert = readCertificate(certBuffer);
- if (certificateToMatch.equals(cert)) {
- return true;
+ private void assertUninstalled(byte[] caBytes)
+ throws CertificateException, GeneralSecurityException {
+ Certificate caCert = readCertificate(caBytes);
+ assertFalse(isCaCertInstalledAndTrusted(caCert));
+ }
+
+ /**
+ * Whether a given cert, or one a lot like it, has been installed system-wide and is available
+ * to all apps.
+ *
+ * <p>A CA certificate is "installed" if it matches all of the following conditions:
+ * <ul>
+ * <li>{@link DevicePolicyManager#hasCaCertInstalled} returns {@code true}.</li>
+ * <li>{@link DevicePolicyManager#getInstalledCaCerts} lists a matching certificate (not
+ * necessarily exactly the same) in its response.</li>
+ * <li>Any new instances of {@link TrustManager} should report the certificate among their
+ * accepted issuer list -- older instances may keep the set of issuers they were created
+ * with until explicitly refreshed.</li>
+ *
+ * @return {@code true} if installed by all metrics, {@code false} if not installed by any
+ * metric. In any other case an {@link AssertionError} will be thrown.
+ */
+ private boolean isCaCertInstalledAndTrusted(Certificate caCert)
+ throws GeneralSecurityException, CertificateException {
+ boolean installed = mDevicePolicyManager.hasCaCertInstalled(getWho(), caCert.getEncoded());
+
+ boolean listed = false;
+ for (byte[] certBuffer : mDevicePolicyManager.getInstalledCaCerts(getWho())) {
+ if (caCert.equals(readCertificate(certBuffer))) {
+ listed = true;
}
}
- return false;
+
+ boolean trusted = false;
+ final TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ for (TrustManager trustManager : tmf.getTrustManagers()) {
+ if (trustManager instanceof X509TrustManager) {
+ final X509TrustManager tm = (X509TrustManager) trustManager;
+ if (Arrays.asList(tm.getAcceptedIssuers()).contains(caCert)) {
+ trusted = true;
+ }
+ }
+ }
+
+ // All three responses should match - if an installed certificate isn't trusted or (worse)
+ // a trusted certificate isn't even installed we should
+ assertEquals(installed, listed);
+ assertEquals(installed, trusted);
+ return installed;
}
+ /**
+ * Convert an encoded certificate back into a {@link Certificate}.
+ *
+ * Instantiates a fresh CertificateFactory every time for repeatability.
+ */
private static Certificate readCertificate(byte[] certBuffer) throws CertificateException {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(new ByteArrayInputStream(certBuffer));
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
new file mode 100644
index 0000000..e68c884
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsPackageInstallerApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctstestrunner ub-uiautomator
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
new file mode 100644
index 0000000..aaa88f2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.packageinstaller">
+
+ <uses-sdk android:minSdkVersion="21"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <receiver
+ android:name=".ClearDeviceOwnerTest$BasicAdminReceiver"
+ 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>
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.packageinstaller"
+ android:label="Package Installer CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
new file mode 100644
index 0000000..de4a9e1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/res/xml/device_admin.xml
@@ -0,0 +1,3 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+ <uses-policies />
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
similarity index 70%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
rename to hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
index 0eddbee..f994e9e 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
@@ -13,17 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.deviceowner;
+package com.android.cts.packageinstaller;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+
+import com.android.cts.packageinstaller.ClearDeviceOwnerTest.BasicAdminReceiver;
import java.io.File;
import java.io.FileInputStream;
@@ -31,34 +37,41 @@
import java.io.OutputStream;
/**
- * This class tests silent package install and uninstall by a device owner.
+ * Base test case for testing PackageInstaller.
*/
-public class PackageInstallTest extends BaseDeviceOwnerTest {
- private static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
- private static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
+public class BasePackageInstallTest extends InstrumentationTestCase {
+ protected static final String TEST_APP_LOCATION = "/data/local/tmp/CtsSimpleApp.apk";
+ protected static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ protected static final int PACKAGE_INSTALLER_TIMEOUT_MS = 60000; // 60 seconds
private static final String ACTION_INSTALL_COMMIT =
"com.android.cts.deviceowner.INTENT_PACKAGE_INSTALL_COMMIT";
- private static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+ protected static final int PACKAGE_INSTALLER_STATUS_UNDEFINED = -1000;
+ public static final String PACKAGE_NAME = SilentPackageInstallTest.class.getPackage().getName();
+ protected Context mContext;
+ protected UiDevice mDevice;
+ protected DevicePolicyManager mDevicePolicyManager;
private PackageManager mPackageManager;
private PackageInstaller mPackageInstaller;
private PackageInstaller.Session mSession;
- private boolean mCallbackReceived;
- private int mCallbackStatus;
+ protected boolean mCallbackReceived;
+ protected int mCallbackStatus;
+ protected Intent mCallbackIntent;
- private final Object mPackageInstallerTimeoutLock = new Object();
+ protected final Object mPackageInstallerTimeoutLock = new Object();
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mContext.unregisterReceiver(this);
synchronized (mPackageInstallerTimeoutLock) {
mCallbackStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PACKAGE_INSTALLER_STATUS_UNDEFINED);
if (mCallbackStatus == PackageInstaller.STATUS_SUCCESS) {
+ mContext.unregisterReceiver(this);
assertEquals(TEST_APP_PKG, intent.getStringExtra(
PackageInstaller.EXTRA_PACKAGE_NAME));
+ } else if (mCallbackStatus == PackageInstaller.STATUS_PENDING_USER_ACTION) {
+ mCallbackIntent = (Intent) intent.getExtras().get(Intent.EXTRA_INTENT);
}
mCallbackReceived = true;
mPackageInstallerTimeoutLock.notify();
@@ -69,6 +82,10 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ mContext = getInstrumentation().getContext();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mDevicePolicyManager = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
mPackageManager = mContext.getPackageManager();
mPackageInstaller = mPackageManager.getPackageInstaller();
assertNotNull(mPackageInstaller);
@@ -79,7 +96,10 @@
@Override
protected void tearDown() throws Exception {
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ if (mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME) ||
+ mDevicePolicyManager.isProfileOwnerApp(PACKAGE_NAME)) {
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ }
try {
mContext.unregisterReceiver(mBroadcastReceiver);
} catch (IllegalArgumentException e) {
@@ -91,33 +111,12 @@
super.tearDown();
}
- public void testSilentInstallUninstall() throws Exception {
- // install the app
- assertInstallPackage();
-
- // uninstall the app again
- assertTrue(tryUninstallPackage());
- assertFalse(isPackageInstalled(TEST_APP_PKG));
+ protected static ComponentName getWho() {
+ return new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
}
- public void testUninstallBlocked() throws Exception {
- // install the app
- assertInstallPackage();
-
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
- assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
- assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
- assertFalse(tryUninstallPackage());
- assertTrue(isPackageInstalled(TEST_APP_PKG));
-
- mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
- assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
- assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
- assertTrue(tryUninstallPackage());
+ protected void assertInstallPackage() throws Exception {
assertFalse(isPackageInstalled(TEST_APP_PKG));
- }
-
- private void assertInstallPackage() throws Exception {
synchronized (mPackageInstallerTimeoutLock) {
mCallbackReceived = false;
mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
@@ -134,7 +133,7 @@
assertTrue(isPackageInstalled(TEST_APP_PKG));
}
- private boolean tryUninstallPackage() throws Exception {
+ protected boolean tryUninstallPackage() throws Exception {
assertTrue(isPackageInstalled(TEST_APP_PKG));
synchronized (mPackageInstallerTimeoutLock) {
mCallbackReceived = false;
@@ -151,7 +150,7 @@
}
}
- private void installPackage(String packageLocation) throws Exception {
+ protected void installPackage(String packageLocation) throws Exception {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = mPackageInstaller.createSession(params);
@@ -184,11 +183,11 @@
mContext,
sessionId,
broadcastIntent,
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent.getIntentSender();
}
- private boolean isPackageInstalled(String packageName) {
+ protected boolean isPackageInstalled(String packageName) {
try {
PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
return pi != null;
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
new file mode 100644
index 0000000..a06271b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ClearDeviceOwnerTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.packageinstaller;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Base class for profile and device based tests.
+ *
+ * This class handles making sure that the test is the profile or device owner and that it has an
+ * active admin registered, so that all tests may assume these are done.
+ */
+public class ClearDeviceOwnerTest extends InstrumentationTestCase {
+
+ public static class BasicAdminReceiver extends DeviceAdminReceiver {
+ }
+
+ public static final String PACKAGE_NAME = BasicAdminReceiver.class.getPackage().getName();
+ public static final ComponentName ADMIN_RECEIVER_COMPONENT = new ComponentName(
+ PACKAGE_NAME, BasicAdminReceiver.class.getName());
+
+ private DevicePolicyManager mDevicePolicyManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager)
+ getInstrumentation().getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
+ assertNotNull(mDevicePolicyManager);
+
+ assertTrue(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+ assertTrue("App is not device owner", mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ removeActiveAdmin(ADMIN_RECEIVER_COMPONENT);
+ mDevicePolicyManager.clearDeviceOwnerApp(PACKAGE_NAME);
+ assertFalse(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
+ assertFalse(mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+
+ super.tearDown();
+ }
+
+ // This test clears the device owner and active admin on tearDown(). To be called from the host
+ // side test once a test case is finished.
+ public void testClearDeviceOwner() {
+ }
+
+ private void removeActiveAdmin(ComponentName cn) throws InterruptedException {
+ if (mDevicePolicyManager.isAdminActive(cn)) {
+ mDevicePolicyManager.removeActiveAdmin(cn);
+ for (int i = 0; i < 1000 && mDevicePolicyManager.isAdminActive(cn); i++) {
+ Thread.sleep(100);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
new file mode 100644
index 0000000..96affae
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/ManualPackageInstallTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.packageinstaller;
+
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * This class tests manual package install and uninstall by a device owner.
+ */
+public class ManualPackageInstallTest extends BasePackageInstallTest {
+ private static final int AUTOMATOR_WAIT_TIMEOUT = 5000;
+ private static final int INSTALL_WAIT_TIME = 5000;
+
+ private static final BySelector POPUP_BUTTON_SELECTOR = By
+ .clazz(android.widget.Button.class.getName())
+ .res("android:id/button1")
+ .pkg("com.google.android.packageinstaller");
+ private static final BySelector POPUP_TEXT_SELECTOR = By
+ .clazz(android.widget.TextView.class.getName())
+ .res("android:id/alertTitle")
+ .pkg("com.google.android.packageinstaller");
+ private static final BySelector INSTALL_BUTTON_SELECTOR = By
+ .clazz(android.widget.Button.class.getName())
+ .res("com.android.packageinstaller:id/ok_button")
+ .pkg("com.google.android.packageinstaller");
+
+ public void testManualInstallSucceeded() throws Exception {
+ assertInstallPackage();
+ }
+
+ public void testManualInstallBlocked() throws Exception {
+ synchronized (mPackageInstallerTimeoutLock) {
+ mCallbackReceived = false;
+ mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+ }
+ // Calls the original installPackage which does not click through the install button.
+ super.installPackage(TEST_APP_LOCATION);
+ synchronized (mPackageInstallerTimeoutLock) {
+ try {
+ mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ }
+ assertTrue(mCallbackReceived);
+ assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+ }
+
+ mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(mCallbackIntent);
+
+ automateDismissInstallBlockedDialog();
+
+ // Assuming installation is not synchronous, we should wait a while before checking.
+ Thread.sleep(INSTALL_WAIT_TIME);
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+
+ @Override
+ protected void installPackage(String packageLocation) throws Exception {
+ super.installPackage(packageLocation);
+
+ synchronized (mPackageInstallerTimeoutLock) {
+ try {
+ mPackageInstallerTimeoutLock.wait(PACKAGE_INSTALLER_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ }
+ assertTrue(mCallbackReceived);
+ assertEquals(PackageInstaller.STATUS_PENDING_USER_ACTION, mCallbackStatus);
+ }
+
+ // Use a receiver to listen for package install.
+ synchronized (mPackageInstallerTimeoutLock) {
+ mCallbackReceived = false;
+ mCallbackStatus = PACKAGE_INSTALLER_STATUS_UNDEFINED;
+ }
+
+ mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(mCallbackIntent);
+
+ automateInstallClick();
+ }
+
+ private void automateInstallClick() {
+ mDevice.wait(Until.hasObject(INSTALL_BUTTON_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 button = mDevice.findObject(INSTALL_BUTTON_SELECTOR);
+ assertNotNull("Install button not found", button);
+ button.click();
+ }
+
+ private void automateDismissInstallBlockedDialog() {
+ mDevice.wait(Until.hasObject(POPUP_TEXT_SELECTOR), AUTOMATOR_WAIT_TIMEOUT);
+ UiObject2 text = mDevice.findObject(POPUP_TEXT_SELECTOR);
+ assertNotNull("Alert dialog not found", text);
+ // "OK" button only present in the dialog if it is blocked by policy.
+ UiObject2 button = mDevice.findObject(POPUP_BUTTON_SELECTOR);
+ assertNotNull("OK button not found", button);
+ button.click();
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
new file mode 100644
index 0000000..f1a80b9
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/SilentPackageInstallTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.packageinstaller;
+
+/**
+ * This class tests silent package install and uninstall by a device owner.
+ */
+public class SilentPackageInstallTest extends BasePackageInstallTest {
+ public void testSilentInstallUninstall() throws Exception {
+ // install the app
+ assertInstallPackage();
+
+ // uninstall the app again
+ assertTrue(tryUninstallPackage());
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+
+ public void testUninstallBlocked() throws Exception {
+ // install the app
+ assertInstallPackage();
+
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, true);
+ assertTrue(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+ assertTrue(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+ assertFalse(tryUninstallPackage());
+ assertTrue(isPackageInstalled(TEST_APP_PKG));
+
+ mDevicePolicyManager.setUninstallBlocked(getWho(), TEST_APP_PKG, false);
+ assertFalse(mDevicePolicyManager.isUninstallBlocked(getWho(), TEST_APP_PKG));
+ assertFalse(mDevicePolicyManager.isUninstallBlocked(null, TEST_APP_PKG));
+ assertTrue(tryUninstallPackage());
+ assertFalse(isPackageInstalled(TEST_APP_PKG));
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 650e963..4fc14e4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -17,7 +17,6 @@
package com.android.cts.devicepolicy;
import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.util.AbiUtils;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.InstrumentationResultParser;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -363,4 +362,20 @@
CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
return commandOutput.startsWith("Success:");
}
+
+ protected String getSettings(String namespace, String name, int userId)
+ throws DeviceNotAvailableException {
+ String command = "settings --user " + userId + " get " + namespace + " " + name;
+ String commandOutput = getDevice().executeShellCommand(command);
+ CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+ return commandOutput.replace("\n", "").replace("\r", "");
+ }
+
+ protected void putSettings(String namespace, String name, String value, int userId)
+ throws DeviceNotAvailableException {
+ String command = "settings --user " + userId + " put " + namespace + " " + name
+ + " " + value;
+ String commandOutput = getDevice().executeShellCommand(command);
+ CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 7cb8f3b..8d22638 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,9 +16,7 @@
package com.android.cts.devicepolicy;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
+import java.io.File;
import java.lang.Exception;
/**
@@ -49,6 +47,18 @@
private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
+ private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+ private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+ private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+ private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+ private static final String PACKAGE_INSTALLER_ADMIN_COMPONENT =
+ PACKAGE_INSTALLER_PKG + "/" + ".ClearDeviceOwnerTest$BasicAdminReceiver";
+ private static final String PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS =
+ PACKAGE_INSTALLER_PKG + ".ClearDeviceOwnerTest";
+
+ @Override
public void tearDown() throws Exception {
if (mHasFeature) {
getDevice().uninstallPackage(DEVICE_OWNER_PKG);
@@ -117,4 +127,28 @@
"testRemoveAccounts", 0));
}
}
+
+ public void testSilentPackageInstall() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ try {
+ // Install the test and prepare the test apk.
+ installApp(PACKAGE_INSTALLER_APK);
+ assertTrue(setDeviceOwner(PACKAGE_INSTALLER_ADMIN_COMPONENT));
+
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+ assertTrue(runDeviceTests(PACKAGE_INSTALLER_PKG,
+ PACKAGE_INSTALLER_PKG + ".SilentPackageInstallTest"));
+ } finally {
+ assertTrue("Failed to remove device owner.", runDeviceTests(PACKAGE_INSTALLER_PKG,
+ PACKAGE_INSTALLER_CLEAR_DEVICE_OWNER_TEST_CLASS));
+ String command = "rm " + TEST_APP_LOCATION + apk.getName();
+ String commandOutput = getDevice().executeShellCommand(command);
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ getDevice().uninstallPackage(PACKAGE_INSTALLER_PKG);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 439c85f..43e6730 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -20,6 +20,8 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
+import java.io.File;
+
/**
* Set of tests for usecases that apply to profile and device owner.
* This class is the base class of MixedProfileOwnerTest and MixedDeviceOwnerTest and is abstract
@@ -41,8 +43,18 @@
private static final String CERT_INSTALLER_PKG = "com.android.cts.certinstaller";
private static final String CERT_INSTALLER_APK = "CtsCertInstallerApp.apk";
+ private static final String TEST_APP_APK = "CtsSimpleApp.apk";
+ private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+ private static final String TEST_APP_LOCATION = "/data/local/tmp/";
+
+ private static final String PACKAGE_INSTALLER_PKG = "com.android.cts.packageinstaller";
+ private static final String PACKAGE_INSTALLER_APK = "CtsPackageInstallerApp.apk";
+
protected static final int USER_OWNER = 0;
+ private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
+ private static final String CLEAR_RESTRICTION_COMMAND = "clear-restriction";
+
// ID of the user all tests are run as. For device owner this will be 0, for profile owner it
// is the user id of the created profile.
protected int mUserId;
@@ -167,7 +179,6 @@
executeDeviceTestClass(".ApplicationHiddenTest");
}
- // TODO: Remove AccountManagementTest from XTS after GTS is released for MNC.
public void testAccountManagement() throws Exception {
if (!mHasFeature) {
return;
@@ -206,6 +217,49 @@
}
}
+ public void testPackageInstallUserRestrictions() throws Exception {
+ // UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES
+ final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+ final String UNKNOWN_SOURCES_SETTING = "install_non_market_apps";
+ final String SECURE_SETTING_CATEGORY = "secure";
+ final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ String unknownSourceSetting = null;
+ try {
+ // Install the test and prepare the test apk.
+ installApp(PACKAGE_INSTALLER_APK);
+ assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
+
+ // Add restrictions and test if we can install the apk.
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ ADD_RESTRICTION_COMMAND, mUserId);
+ assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+ "testManualInstallBlocked", mUserId));
+
+ // Clear restrictions and test if we can install the apk.
+ changeUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ CLEAR_RESTRICTION_COMMAND, mUserId);
+
+ // Enable Unknown sources in Settings.
+ unknownSourceSetting =
+ getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId);
+ putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, "1", mUserId);
+ assertEquals("1",
+ getSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, mUserId));
+ assertTrue(runDeviceTestsAsUser(PACKAGE_INSTALLER_PKG, ".ManualPackageInstallTest",
+ "testManualInstallSucceeded", mUserId));
+ } finally {
+ String command = "rm " + TEST_APP_LOCATION + apk.getName();
+ getDevice().executeShellCommand(command);
+ getDevice().uninstallPackage(TEST_APP_PKG);
+ getDevice().uninstallPackage(PACKAGE_INSTALLER_APK);
+ if (unknownSourceSetting != null) {
+ putSettings(SECURE_SETTING_CATEGORY, UNKNOWN_SOURCES_SETTING, unknownSourceSetting,
+ mUserId);
+ }
+ }
+ }
+
protected void executeDeviceTestClass(String className) throws Exception {
assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId));
}
@@ -213,4 +267,18 @@
protected void executeDeviceTestMethod(String className, String testName) throws Exception {
assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, testName, mUserId));
}
+
+ private void changeUserRestrictionForUser(String key, String command, int userId)
+ throws DeviceNotAvailableException {
+ String adbCommand = "am start -W --user " + userId
+ + " -c android.intent.category.DEFAULT "
+ + " --es extra-command " + command
+ + " --es extra-restriction-key " + key
+ + " " + DEVICE_ADMIN_PKG + "/.UserRestrictionActivity";
+ String commandOutput = getDevice().executeShellCommand(adbCommand);
+ CLog.logAndDisplay(LogLevel.INFO,
+ "Output for command " + adbCommand + ": " + commandOutput);
+ assertTrue("Command was expected to succeed " + commandOutput,
+ commandOutput.contains("Status: ok"));
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 4f267d1..96ca469 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -16,12 +16,6 @@
package com.android.cts.devicepolicy;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-
/**
* Set of tests for Device Owner use cases.
*/
@@ -35,10 +29,6 @@
private static final String MANAGED_PROFILE_ADMIN =
MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
- private static final String TEST_APP_APK = "CtsSimpleApp.apk";
- private static final String TEST_APP_PKG = "com.android.cts.launcherapps.simpleapp";
- private static final String TEST_APP_LOCATION = "/data/local/tmp/";
-
private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
@@ -93,19 +83,6 @@
}
}
- public void testPackageInstall() throws Exception {
- final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
- try {
- getDevice().uninstallPackage(TEST_APP_PKG);
- assertTrue(getDevice().pushFile(apk, TEST_APP_LOCATION + apk.getName()));
- executeDeviceOwnerTest("PackageInstallTest");
- } finally {
- String command = "rm " + TEST_APP_LOCATION + apk.getName();
- String commandOutput = getDevice().executeShellCommand(command);
- getDevice().uninstallPackage(TEST_APP_PKG);
- }
- }
-
public void testSystemUpdatePolicy() throws Exception {
executeDeviceOwnerTest("SystemUpdatePolicyTest");
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
index 8da189f..1d5dd11 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -25,11 +25,13 @@
* apps.
*/
public class LauncherAppsMultiUserTest extends BaseLauncherAppsTest {
+ private static final String FEATURE_LIVE_TV = "android.software.live_tv";
private int mSecondaryUserId;
private int mSecondaryUserSerialNumber;
private boolean mMultiUserSupported;
+ private boolean mHasLiveTvFeature;
@Override
protected void setUp() throws Exception {
@@ -37,6 +39,7 @@
// We need multi user to be supported in order to create a secondary user
// and api level 21 to support LauncherApps
mMultiUserSupported = getMaxNumberOfUsersSupported() > 1 && getDevice().getApiLevel() >= 21;
+ mHasLiveTvFeature = hasDeviceFeature(FEATURE_LIVE_TV);
if (mMultiUserSupported) {
removeTestUsers();
@@ -58,7 +61,7 @@
}
public void testGetActivitiesForNonProfileFails() throws Exception {
- if (!mMultiUserSupported) {
+ if (!mMultiUserSupported || mHasLiveTvFeature) {
return;
}
installApp(SIMPLE_APP_APK);
@@ -73,7 +76,7 @@
}
public void testNoLauncherCallbackPackageAddedSecondaryUser() throws Exception {
- if (!mMultiUserSupported) {
+ if (!mMultiUserSupported || mHasLiveTvFeature) {
return;
}
startCallbackService();
diff --git a/tests/tests/netlegacy22/Android.mk b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
similarity index 66%
rename from tests/tests/netlegacy22/Android.mk
rename to hostsidetests/dumpsys/FramestatsTestApp/Android.mk
index 3174652..1104523 100644
--- a/tests/tests/netlegacy22/Android.mk
+++ b/hostsidetests/dumpsys/FramestatsTestApp/Android.mk
@@ -12,5 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Build the API tests and the permissions tests using their own makefiles.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_PACKAGE_NAME := CtsFramestatsTestApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml b/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..3a9f902
--- /dev/null
+++ b/hostsidetests/dumpsys/FramestatsTestApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.framestatstestapp">
+ <!--
+ A simple app that draws at least one frame. Used by framestats
+ test.
+ -->
+ <application>
+ <activity android:name=".FramestatsTestAppActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java b/hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
similarity index 64%
rename from tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java
rename to hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
index ae570d8..7370508 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/DisableContextActivity.java
+++ b/hostsidetests/dumpsys/FramestatsTestApp/src/com/android/cts/framestatstestapp/FramestatsTestAppActivity.java
@@ -13,26 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package android.assist.testapp;
+package com.android.cts.framestatstestapp;
import android.app.Activity;
-import android.content.Intent;
import android.os.Bundle;
-import android.util.Log;
+import android.os.Trace;
+import android.view.View;
-public class DisableContextActivity extends Activity {
- static final String TAG = "TestApp";
-
+public class FramestatsTestAppActivity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Log.i(TAG, "TestApp created");
- setContentView(R.layout.test_app);
+ View v = new View(this);
+ v.setBackgroundColor(0xFF00FF00);
+ setContentView(v);
}
-
- @Override
- public void onResume() {
- super.onResume();
- }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index a787cdd..0daae03 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,11 +16,15 @@
package android.dumpsys.cts;
-import com.android.ddmlib.Log;
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;
@@ -28,8 +32,10 @@
/**
* Test to check the format of the dumps of various services (currently only procstats is tested).
*/
-public class DumpsysHostTest extends DeviceTestCase {
+public class DumpsysHostTest extends DeviceTestCase implements IBuildReceiver {
private static final String TAG = "DumpsysHostTest";
+ private static final String TEST_APK = "CtsFramestatsTestApp.apk";
+ private static final String TEST_PKG = "com.android.cts.framestatstestapp";
/**
* A reference to the device under test.
@@ -815,17 +821,38 @@
*/
public void testGfxinfoFramestats() throws Exception {
final String MARKER = "---PROFILEDATA---";
- final int TIMESTAMP_COUNT = 14;
- String frameinfo = mDevice.executeShellCommand("dumpsys gfxinfo com.android.systemui framestats");
- assertNotNull(frameinfo);
- assertTrue(frameinfo.length() > 0);
- int profileStart = frameinfo.indexOf(MARKER);
- int profileEnd = frameinfo.indexOf(MARKER, profileStart + 1);
- assertTrue(profileStart >= 0);
- assertTrue(profileEnd > profileStart);
- String profileData = frameinfo.substring(profileStart + MARKER.length(), profileEnd);
- assertTrue(profileData.length() > 0);
+ try {
+ // cleanup test apps that might be installed from previous partial test run
+ getDevice().uninstallPackage(TEST_PKG);
+
+ // install the test app
+ File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+ String installResult = getDevice().installPackage(testAppFile, false);
+ assertNull(
+ String.format("failed to install atrace test app. Reason: %s", installResult),
+ installResult);
+
+ getDevice().executeShellCommand("am start -W " + TEST_PKG);
+
+ String frameinfo = mDevice.executeShellCommand("dumpsys gfxinfo " +
+ TEST_PKG + " framestats");
+ assertNotNull(frameinfo);
+ assertTrue(frameinfo.length() > 0);
+ int profileStart = frameinfo.indexOf(MARKER);
+ int profileEnd = frameinfo.indexOf(MARKER, profileStart + 1);
+ assertTrue(profileStart >= 0);
+ assertTrue(profileEnd > profileStart);
+ String profileData = frameinfo.substring(profileStart + MARKER.length(), profileEnd);
+ assertTrue(profileData.length() > 0);
+ validateProfileData(profileData);
+ } finally {
+ getDevice().uninstallPackage(TEST_PKG);
+ }
+ }
+
+ private void validateProfileData(String profileData) throws IOException {
+ final int TIMESTAMP_COUNT = 14;
boolean foundAtLeastOneRow = false;
try (BufferedReader reader = new BufferedReader(
new StringReader(profileData))) {
@@ -872,6 +899,16 @@
assertTrue(foundAtLeastOneRow);
}
+ private CtsBuildHelper mCtsBuild;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ }
+
private static long assertInteger(String input) {
try {
return Long.parseLong(input);
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
index a0d3167..abb1ac4 100644
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
@@ -589,9 +589,9 @@
assertDomainN("u:r:zygote:s0", "zygote", "zygote64");
}
- /* drm server is always present */
+ /* Checks drmserver for devices that require it */
public void testDrmServerDomain() throws DeviceNotAvailableException {
- assertDomainOne("u:r:drmserver:s0", "/system/bin/drmserver");
+ assertDomainZeroOrOne("u:r:drmserver:s0", "/system/bin/drmserver");
}
/* Media server is always running */
diff --git a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
old mode 100644
new mode 100755
index 63c7472..0e11111
--- a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
+++ b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
@@ -77,27 +77,42 @@
* @param threshold maximum difference per channel
* @return {@code true} if the images are similar, false otherwise
*/
- private static boolean compare(BufferedImage expected, BufferedImage actual,
- int threshold) {
- final int w = actual.getWidth();
- final int h = actual.getHeight();
- if (w != expected.getWidth() || h != expected.getHeight()) {
+ private static int getAlphaScaledBlue(final int color) {
+ return (color & 0x000000FF) * getAlpha(color) / 255;
+ }
+
+ private static int getAlphaScaledGreen(final int color) {
+ return ((color & 0x0000FF00) >> 8) * getAlpha(color) / 255;
+ }
+
+ private static int getAlphaScaledRed(final int color) {
+ return ((color & 0x00FF0000) >> 16) * getAlpha(color) / 255;
+ }
+
+ private static int getAlpha(final int color) {
+ // use logical shift for keeping an unsigned value
+ return (color & 0xFF000000) >>> 24;
+ }
+
+ private static boolean compare(BufferedImage reference, BufferedImage generated, int threshold) {
+ final int w = generated.getWidth();
+ final int h = generated.getHeight();
+ if (w != reference.getWidth() || h != reference.getHeight()) {
return false;
}
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
- final int p1 = expected.getRGB(i, j);
- final int p2 = actual.getRGB(i, j);
- final int dr = (p1 & 0x000000FF) - (p2 & 0x000000FF);
- final int dg = ((p1 & 0x0000FF00) - (p2 & 0x0000FF00)) >> 8;
- final int db = ((p1 & 0x00FF0000) - (p2 & 0x00FF0000)) >> 16;
- final int da = ((p1 & 0xFF000000) - (p2 & 0xFF000000)) >> 24;
+ final int p1 = reference.getRGB(i, j);
+ final int p2 = generated.getRGB(i, j);
+
+ final int dr = getAlphaScaledRed(p1) - getAlphaScaledRed(p2);
+ final int dg = getAlphaScaledGreen(p1) - getAlphaScaledGreen(p2);
+ final int db = getAlphaScaledBlue(p1) - getAlphaScaledBlue(p2);
if (Math.abs(db) > threshold ||
Math.abs(dg) > threshold ||
- Math.abs(dr) > threshold ||
- Math.abs(da) > threshold) {
+ Math.abs(dr) > threshold) {
return false;
}
}
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 7e2bfe3..b3ebbad 100755
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -330,13 +330,34 @@
ex.release();
}
}
- return false;
+ return true;
}
public static boolean checkCodecsForPath(Context context, String path) {
return check(hasCodecsForPath(context, path), "no decoder found");
}
+ public static boolean hasCodecForDomain(boolean encoder, String domain) {
+ for (MediaCodecInfo info : sMCL.getCodecInfos()) {
+ if (encoder != info.isEncoder()) {
+ continue;
+ }
+
+ for (String type : info.getSupportedTypes()) {
+ if (type.toLowerCase().startsWith(domain.toLowerCase() + "/")) {
+ Log.i(TAG, "found codec " + info.getName() + " for mime " + type);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean checkCodecForDomain(boolean encoder, String domain) {
+ return check(hasCodecForDomain(encoder, domain),
+ "no " + domain + (encoder ? " encoder" : " decoder") + " found");
+ }
+
private static boolean hasCodecForMime(boolean encoder, String mime) {
for (MediaCodecInfo info : sMCL.getCodecInfos()) {
if (encoder != info.isEncoder()) {
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
index b8e2acf..16504fd 100644
--- a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.cpp
@@ -22,6 +22,14 @@
// Used to center the grid on the screen.
#define CENTER_GRID(x) ((((x) * 2.0 + 1) - OFFSCREEN_GRID_SIZE) / OFFSCREEN_GRID_SIZE)
+// Leave a good error message if something fails.
+#define EGL_RESULT_CHECK(X) do { \
+ EGLint error = eglGetError(); \
+ if (!(X) || error != EGL_SUCCESS) { \
+ ALOGE("EGL error '%d' at %s:%d", error, __FILE__, __LINE__);\
+ return false; \
+ } \
+ } while (0)
static const int FBO_NUM_VERTICES = 6;
@@ -66,7 +74,7 @@
EGL_NONE };
static const EGLint configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
@@ -78,53 +86,60 @@
static const int FBO_SIZE = 128;
-Renderer::Renderer(ANativeWindow* window, bool offscreen, int workload) :
- mOffscreen(offscreen), mWindow(window), mEglDisplay(EGL_NO_DISPLAY),
- mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT), mWorkload(workload) {
+Renderer::Renderer(EGLNativeWindowType window, bool offscreen) :
+ mOffscreen(offscreen), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE),
+ mEglContext(EGL_NO_CONTEXT), mWindow(window) {
}
-bool Renderer::setUp() {
+bool Renderer::eglSetUp() {
SCOPED_TRACE();
mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (EGL_NO_DISPLAY == mEglDisplay || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+ EGL_RESULT_CHECK(mEglDisplay != EGL_NO_DISPLAY);
EGLint major;
EGLint minor;
- if (!eglInitialize(mEglDisplay, &major, &minor) || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+ EGL_RESULT_CHECK(eglInitialize(mEglDisplay, &major, &minor));
EGLint numConfigs = 0;
- if (!eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
- || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+ EGL_RESULT_CHECK(eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
+ && (numConfigs > 0));
mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mWindow, NULL);
- if (EGL_NO_SURFACE == mEglSurface || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+ EGL_RESULT_CHECK(mEglSurface != EGL_NO_SURFACE);
mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
- if (EGL_NO_CONTEXT == mEglContext || EGL_SUCCESS != eglGetError()) {
- return false;
+ EGL_RESULT_CHECK(mEglContext != EGL_NO_CONTEXT);
+
+ EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
+ EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth));
+ EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight));
+
+ return true;
+}
+
+void Renderer::eglTearDown() {
+ SCOPED_TRACE();
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = EGL_NO_CONTEXT;
}
- if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
- || EGL_SUCCESS != eglGetError()) {
- return false;
+ if (mEglSurface != EGL_NO_SURFACE) {
+ mEglSurface = EGL_NO_SURFACE;
}
- if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth)
- || EGL_SUCCESS != eglGetError()) {
- return false;
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ mEglDisplay = EGL_NO_DISPLAY;
}
- if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight)
- || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+}
+
+bool Renderer::setUp(int /*workload*/) {
+ SCOPED_TRACE();
+
+ EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
if (mOffscreen) {
mFboWidth = FBO_SIZE;
@@ -178,6 +193,7 @@
ALOGE("GLError %d in setUp", err);
return false;
}
+
return true;
}
@@ -202,29 +218,14 @@
ALOGE("GLError %d in tearDown", err);
return false;
}
- if (mEglContext != EGL_NO_CONTEXT) {
- eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = EGL_NO_CONTEXT;
- }
- if (mEglSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = EGL_NO_SURFACE;
- }
- if (mEglDisplay != EGL_NO_DISPLAY) {
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate(mEglDisplay);
- mEglDisplay = EGL_NO_DISPLAY;
- }
- return EGL_SUCCESS == eglGetError();
+ return true;
}
bool Renderer::draw() {
SCOPED_TRACE();
- if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
- || EGL_SUCCESS != eglGetError()) {
- return false;
- }
+
+ EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, mWidth, mHeight);
@@ -287,5 +288,6 @@
return false;
}
- return eglSwapBuffers(mEglDisplay, mEglSurface);
+ EGL_RESULT_CHECK(eglSwapBuffers(mEglDisplay, mEglSurface));
+ return true;
}
diff --git a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
index caa1634..3c62a26 100644
--- a/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
+++ b/suite/cts/deviceTests/opengl/jni/graphics/Renderer.h
@@ -14,17 +14,18 @@
#ifndef RENDERER_H
#define RENDERER_H
-#include <android/native_window.h>
-
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
class Renderer {
public:
- Renderer(ANativeWindow* window, bool offscreen, int workload);
- virtual bool setUp();
+ Renderer(EGLNativeWindowType window, bool offscreen);
+ virtual bool setUp(int workload);
virtual bool tearDown();
+ bool eglSetUp();
+ void eglTearDown();
+
bool draw();
virtual void drawWorkload() = 0;
virtual ~Renderer() {};
@@ -32,7 +33,6 @@
static const int OFFSCREEN_GRID_SIZE = 10;
bool mOffscreen;
protected:
- ANativeWindow* mWindow;
EGLDisplay mEglDisplay;
EGLSurface mEglSurface;
EGLContext mEglContext;
@@ -40,7 +40,6 @@
GLuint mProgramId;
EGLint mWidth;
EGLint mHeight;
- int mWorkload;
int mFboWidth;// Frame buffer width
int mFboHeight;// Frame buffer height
GLuint mFboId;// Frame buffer id
@@ -52,5 +51,7 @@
GLuint mFboYOffsetUniformHandle;// Frame buffer y offset uniform handle
GLuint mFboPositionHandle;// Frame buffer position handle
GLuint mFboTexCoordHandle;// Frame buffer texture coordinate handle
+private:
+ EGLNativeWindowType mWindow;
};
#endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp b/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
index 9d39af9..856da1e 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/GLPrimitive.cpp
@@ -28,16 +28,24 @@
// Holds the current benchmark's renderer.
Renderer* gRenderer = NULL;
+ANativeWindow* gNativeWindow = NULL;
+
+enum {
+ FULL_PIPELINE_BENCHMARK = 0,
+ PIXEL_OUTPUT_BENCHMARK = 1,
+ SHADER_PERF_BENCHMARK = 2,
+ CONTEXT_SWITCH_BENCHMARK = 3
+};
extern "C" JNIEXPORT jboolean JNICALL
Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_startBenchmark(
- JNIEnv* env, jclass clazz, jint numFrames, jdoubleArray frameTimes) {
+ JNIEnv* env, jclass /*clazz*/, jint workload, jint numFrames, jdoubleArray frameTimes) {
if (gRenderer == NULL) {
return false;
}
// Sets up the renderer.
- bool success = gRenderer->setUp();
+ bool success = gRenderer->setUp(workload);
// Records the start time.
double start = GLUtils::currentTimeMillis();
@@ -60,41 +68,56 @@
double times[] = {start, end};
env->SetDoubleArrayRegion(frameTimes, 0, 2, times);
- // Tears down and deletes the renderer.
success = gRenderer->tearDown() && success;
- delete gRenderer;
- gRenderer = NULL;
return success;
}
// The following functions create the renderers for the various benchmarks.
extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupFullPipelineBenchmark(
- JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
- gRenderer = new FullPipelineRenderer(
- ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupPixelOutputBenchmark(
- JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
- gRenderer = new PixelOutputRenderer(
- ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupShaderPerfBenchmark(
- JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
- gRenderer = new ShaderPerfRenderer(
- ANativeWindow_fromSurface(env, surface), offscreen, workload);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupContextSwitchBenchmark(
- JNIEnv* env, jclass clazz, jobject surface, jboolean offscreen, jint workload) {
- if (workload <= 8) {
- // This test uses 8 iterations, so workload can't be more than 8.
- gRenderer = new ContextSwitchRenderer(
- ANativeWindow_fromSurface(env, surface), offscreen, workload);
+Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_setupBenchmark(
+ JNIEnv* env, jclass /*clazz*/, jobject surface, jint benchmark,
+ jboolean offscreen) {
+ gNativeWindow = ANativeWindow_fromSurface(env, surface);
+ switch (benchmark) {
+ case FULL_PIPELINE_BENCHMARK:
+ gRenderer = new FullPipelineRenderer(gNativeWindow, offscreen);
+ break;
+ case PIXEL_OUTPUT_BENCHMARK:
+ gRenderer = new PixelOutputRenderer(gNativeWindow, offscreen);
+ break;
+ case SHADER_PERF_BENCHMARK:
+ gRenderer = new ShaderPerfRenderer(gNativeWindow, offscreen);
+ break;
+ case CONTEXT_SWITCH_BENCHMARK:
+ gRenderer = new ContextSwitchRenderer(gNativeWindow, offscreen);
+ break;
+ default:
+ ALOGE("Unknown benchmark '%d'", benchmark);
+ ANativeWindow_release(gNativeWindow);
+ gNativeWindow = NULL;
+ return;
}
+
+ // Set up call will log error conditions
+ if (!gRenderer->eglSetUp()) {
+ delete gRenderer;
+ gRenderer = NULL;
+
+ ANativeWindow_release(gNativeWindow);
+ gNativeWindow = NULL;
+ }
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_android_cts_opengl_primitive_GLPrimitiveActivity_tearDownBenchmark(
+ JNIEnv* /*env*/, jclass /*clazz*/) {
+ if (gRenderer == NULL) {
+ return;
+ }
+ gRenderer->eglTearDown();
+ delete gRenderer;
+ gRenderer = NULL;
+
+ ANativeWindow_release(gNativeWindow);
+ gNativeWindow = NULL;
}
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
index 7fd4093..1127d88 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.cpp
@@ -74,13 +74,14 @@
" gl_FragColor = texture2D(u_Texture, v_TexCoord);"
"}";
-ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload) :
- Renderer(window, offscreen, workload), mContexts(NULL) {
+ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen) :
+ Renderer(window, offscreen), mContexts(NULL), mWorkload(0) {
}
-bool ContextSwitchRenderer::setUp() {
+bool ContextSwitchRenderer::setUp(int workload) {
SCOPED_TRACE();
- if (!Renderer::setUp()) {
+ mWorkload = workload;
+ if (!Renderer::setUp(workload)) {
return false;
}
@@ -137,7 +138,7 @@
bool ContextSwitchRenderer::tearDown() {
SCOPED_TRACE();
if (mContexts) {
- // Destroy the contexts, the main one will be handled by Renderer::tearDown().
+ // Destroy the contexts, the main one will be handled by Renderer::eglTearDown().
for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
if (mOffscreen) {
if (mFboIds[i] != 0) {
@@ -146,6 +147,7 @@
mFboIds[i] = 0;
}
}
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mEglDisplay, mContexts[i]);
}
delete[] mContexts;
@@ -163,6 +165,11 @@
void ContextSwitchRenderer::drawWorkload() {
SCOPED_TRACE();
+
+ if (mWorkload > 8) {
+ return; // This test does not support higher workloads.
+ }
+
// Set the background clear color to black.
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@@ -216,6 +223,7 @@
}
}
+ eglWaitSyncKHR(mEglDisplay, fence, 0);
eglDestroySyncKHR(mEglDisplay, fence);
// Switch back to the main context.
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
index 51a4376..ae320ff 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/contextswitch/ContextSwitchRenderer.h
@@ -18,9 +18,9 @@
class ContextSwitchRenderer: public Renderer {
public:
- ContextSwitchRenderer(ANativeWindow* window, bool offscreen, int workload);
+ ContextSwitchRenderer(ANativeWindow* window, bool offscreen);
virtual ~ContextSwitchRenderer() {};
- bool setUp();
+ bool setUp(int workload);
bool tearDown();
void drawWorkload();
private:
@@ -31,6 +31,7 @@
GLuint mTranslateUniformHandle;
GLuint mPositionHandle;
GLuint mTexCoordHandle;
+ int mWorkload;
};
#endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
index 97462b5..0f75f81 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.cpp
@@ -91,15 +91,15 @@
" gl_FragColor = (diffuse * texture2D(u_Texture, v_TexCoordinate));\n"
"}";
-FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload) :
- Renderer(window, offscreen, workload), mProgram(NULL), mSceneGraph(NULL),
+FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen) :
+ Renderer(window, offscreen), mProgram(NULL), mSceneGraph(NULL),
mModelMatrix(NULL), mViewMatrix(NULL), mProjectionMatrix(NULL), mMesh(NULL),
mTextureId(0) {
}
-bool FullPipelineRenderer::setUp() {
+bool FullPipelineRenderer::setUp(int workload) {
SCOPED_TRACE();
- if (!Renderer::setUp()) {
+ if (!Renderer::setUp(workload)) {
return false;
}
@@ -147,7 +147,7 @@
return false;
}
- float count = mWorkload * mWorkload;
+ float count = workload * workload;
float middle = count / 2.0f;
float scale = 2.0f / count;
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
index 84616b4..ce44760 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/fullpipeline/FullPipelineRenderer.h
@@ -22,9 +22,9 @@
class FullPipelineRenderer: public Renderer {
public:
- FullPipelineRenderer(ANativeWindow* window, bool offscreen, int workload);
+ FullPipelineRenderer(ANativeWindow* window, bool offscreen);
virtual ~FullPipelineRenderer() {};
- bool setUp();
+ bool setUp(int workload);
bool tearDown();
void drawWorkload();
private:
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
index 287ebfb..3a3b9d1 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.cpp
@@ -50,13 +50,14 @@
" gl_FragColor = texture2D(u_Texture, v_TexCoord);"
"}";
-PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload) :
- Renderer(window, offscreen, workload) {
+PixelOutputRenderer::PixelOutputRenderer(ANativeWindow* window, bool offscreen) :
+ Renderer(window, offscreen), mWorkload(0) {
}
-bool PixelOutputRenderer::setUp() {
+bool PixelOutputRenderer::setUp(int workload) {
SCOPED_TRACE();
- if (!Renderer::setUp()) {
+ mWorkload = workload;
+ if (!Renderer::setUp(workload)) {
return false;
}
@@ -80,6 +81,11 @@
bool PixelOutputRenderer::tearDown() {
SCOPED_TRACE();
+ if (mProgramId != 0)
+ {
+ glDeleteProgram(mProgramId);
+ mProgramId = 0;
+ }
if (mTextureId != 0) {
glDeleteTextures(1, &mTextureId);
mTextureId = 0;
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
index e6b5692..816da6a 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/pixeloutput/PixelOutputRenderer.h
@@ -18,9 +18,9 @@
class PixelOutputRenderer: public Renderer {
public:
- PixelOutputRenderer(ANativeWindow* window, bool offscreen, int workload);
+ PixelOutputRenderer(ANativeWindow* window, bool offscreen);
virtual ~PixelOutputRenderer() {};
- bool setUp();
+ bool setUp(int workload);
bool tearDown();
void drawWorkload();
private:
@@ -28,6 +28,7 @@
GLuint mTextureUniformHandle;
GLuint mPositionHandle;
GLuint mTexCoordHandle;
+ int mWorkload;
};
#endif
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
index 1cbc839..a02f4fe 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.cpp
@@ -91,13 +91,13 @@
return destAddr - destStart;
}
-ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload) :
- Renderer(window, offscreen, workload) {
+ShaderPerfRenderer::ShaderPerfRenderer(ANativeWindow* window, bool offscreen) :
+ Renderer(window, offscreen) {
}
-bool ShaderPerfRenderer::setUp() {
+bool ShaderPerfRenderer::setUp(int workload) {
SCOPED_TRACE();
- if (!Renderer::setUp()) {
+ if (!Renderer::setUp(workload)) {
return false;
}
@@ -106,7 +106,7 @@
// Add the first part.
int index = charCopy(SP_FRAGMENT_1, spFragment, 0);
// Add the count, overwriting the '\0' added by charCopy.
- spFragment[index - 1] = (char) (((int) '0') + mWorkload);
+ spFragment[index - 1] = (char) (((int) '0') + workload);
// Add the second part.
index += charCopy(SP_FRAGMENT_2, spFragment, index);
// Create program.
diff --git a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
index 52fac43..c804202 100644
--- a/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/primitive/shaderperf/ShaderPerfRenderer.h
@@ -18,9 +18,9 @@
class ShaderPerfRenderer: public Renderer {
public:
- ShaderPerfRenderer(ANativeWindow* window, bool offscreen, int workload);
+ ShaderPerfRenderer(ANativeWindow* window, bool offscreen);
virtual ~ShaderPerfRenderer() {};
- bool setUp();
+ bool setUp(int workload);
void drawWorkload();
private:
GLuint mTextureId;
diff --git a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp b/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
index 1857848..dc0b4e2 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
+++ b/suite/cts/deviceTests/opengl/jni/reference/GLReference.cpp
@@ -23,7 +23,7 @@
extern "C" JNIEXPORT jboolean JNICALL
Java_com_android_cts_opengl_reference_GLGameActivity_startBenchmark(
- JNIEnv* env, jclass clazz, jobject assetManager, jobject surface, jint numFrames,
+ JNIEnv* env, jclass /*clazz*/, jobject assetManager, jobject surface, jint numFrames,
jdoubleArray setUpTimes, jdoubleArray updateTimes, jdoubleArray renderTimes) {
GLUtils::setEnvAndAssetManager(env, assetManager);
@@ -32,9 +32,10 @@
return false;
}
- ReferenceRenderer* renderer = new ReferenceRenderer(ANativeWindow_fromSurface(env, surface));
-
- bool success = renderer->setUp();
+ ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
+ ReferenceRenderer* renderer = new ReferenceRenderer(nativeWindow);
+ bool success = renderer->eglSetUp();
+ success = renderer->setUp(0) && success;
env->SetDoubleArrayRegion(
setUpTimes, 0, ReferenceRenderer::NUM_SETUP_TIMES, renderer->mSetUpTimes);
@@ -54,7 +55,11 @@
env->SetDoubleArrayRegion(renderTimes, 0, numFrames, renders);
success = renderer->tearDown() && success;
+ renderer->eglTearDown();
delete renderer;
renderer = NULL;
+
+ ANativeWindow_release(nativeWindow);
+
return success;
}
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
index 8f7703e..3b12ee1 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
+++ b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.cpp
@@ -22,10 +22,10 @@
#include <Trace.h>
ReferenceRenderer::ReferenceRenderer(ANativeWindow* window) :
- Renderer(window, false, 0) {
+ Renderer(window, false) {
}
-bool ReferenceRenderer::setUp() {
+bool ReferenceRenderer::setUp(int workload) {
SCOPED_TRACE();
// Reset the times.
for (int i = 0; i < NUM_SETUP_TIMES; i++) {
@@ -33,7 +33,7 @@
}
// Set up OpenGLES.
double start = GLUtils::currentTimeMillis();
- if (!Renderer::setUp()) {
+ if (!Renderer::setUp(workload)) {
return false;
}
mSetUpTimes[0] = GLUtils::currentTimeMillis() - start;
diff --git a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
index d10297a..f5c4b65 100644
--- a/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
+++ b/suite/cts/deviceTests/opengl/jni/reference/ReferenceRenderer.h
@@ -23,7 +23,7 @@
public:
ReferenceRenderer(ANativeWindow* window);
virtual ~ReferenceRenderer() {};
- bool setUp();
+ bool setUp(int workload);
bool tearDown();
bool update(int frame);
void drawWorkload();
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
index 5dc9b88..6defdb7 100644
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
+++ b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveActivity.java
@@ -102,19 +102,12 @@
}
}
- private static native void setupFullPipelineBenchmark(
- Surface surface, boolean offscreen, int workload);
+ private static native boolean setupBenchmark(
+ Surface surface, int benchmark, boolean offscreen);
- private static native void setupPixelOutputBenchmark(
- Surface surface, boolean offscreen, int workload);
+ private static native boolean startBenchmark(int workload, int numFrames, double[] frameTimes);
- private static native void setupShaderPerfBenchmark(
- Surface surface, boolean offscreen, int workload);
-
- private static native void setupContextSwitchBenchmark(
- Surface surface, boolean offscreen, int workload);
-
- private static native boolean startBenchmark(int numFrames, double[] frameTimes);
+ private static native void tearDownBenchmark();
/**
* This thread runs the benchmarks, freeing the UI thread.
@@ -138,36 +131,29 @@
watchDog = new WatchDog(mTimeout, this);
// Used to record the start and end time of the iteration.
double[] times = new double[2];
- for (int i = 0; i < mNumIterations && success; i++) {
- // The workload to use for this iteration.
- int workload = i + 1;
+ try {
// Setup the benchmark.
- switch (mBenchmark) {
- case FullPipeline:
- setupFullPipelineBenchmark(mSurface, mOffscreen, workload);
- break;
- case PixelOutput:
- setupPixelOutputBenchmark(mSurface, mOffscreen, workload);
- break;
- case ShaderPerf:
- setupShaderPerfBenchmark(mSurface, mOffscreen, workload);
- break;
- case ContextSwitch:
- setupContextSwitchBenchmark(mSurface, mOffscreen, workload);
- break;
- }
- watchDog.start();
- // Start benchmark.
- success = startBenchmark(mNumFrames, times);
- watchDog.stop();
-
- if (!success) {
- setException(new Exception("Benchmark failed to run"));
- } else {
- // Calculate FPS.
- mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
+ setupBenchmark(mSurface, mBenchmark.ordinal(), mOffscreen);
+ for (int i = 0; i < mNumIterations && success; i++) {
+ // The workload to use for this iteration.
+ int workload = i + 1;
+ watchDog.start();
+ // Start benchmark.
+ success = startBenchmark(workload, mNumFrames, times);
+ watchDog.stop();
+ if (!success) {
+ setException(new Exception("Benchmark failed to run"));
+ } else {
+ // Calculate FPS.
+ mFpsValues[i] = mNumFrames * 1000.0f / (times[1] - times[0]);
+ }
}
}
+ finally
+ {
+ tearDownBenchmark();
+ }
+
complete();
Log.i(TAG, mBenchmark + " Benchmark Completed");
}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 29c5035..2cb99c4 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -158,6 +158,14 @@
bug: 17508787
},
{
+ description: "This test should be outside of official CTS suite until it is verified for all Nexus devices",
+ names: [
+ "com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions",
+ "com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions"
+ ],
+ bug: 18928535
+},
+{
description: "Test is not yet properly implemented",
names: [
"android.voicesettings.cts.ZenModeTest#testAll"
@@ -254,6 +262,13 @@
bug: 23008511
},
{
+ description: "Light status bar CTS coming in late",
+ names: [
+ "com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons"
+ ],
+ bug: 23427621
+},
+{
description: "known failures",
names: [
"android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching",
@@ -287,5 +302,63 @@
"com.android.cts.app.os.OsHostTests#testNonExportedActivities"
],
bug: 23779168
+},
+{
+ description: "New assist tests that do not yet have a track record.",
+ names: [
+ "android.assist.cts.AssistantContentViewTest",
+ "android.assist.cts.ExtraAssistDataTest",
+ "android.assist.cts.FocusChangeTest",
+ "android.assist.cts.LargeViewHierarchyTest",
+ "android.assist.cts.ScreenshotTest",
+ "android.assist.cts.TextViewTest",
+ "android.assist.cts.WebViewTest"
+ ],
+ bug: 21668302
+},
+{
+ description: "ConnectivityConstraintTest job scheduler not working.",
+ names: [
+ "android.jobscheduler.cts.ConnectivityConstraintTest#testConnectivityConstraintExecutes_withWifi",
+ "android.jobscheduler.cts.ConnectivityConstraintTest#testUnmeteredConstraintExecutes_withWifi"
+ ],
+ bug: 21262226
+},
+{
+ description: "ConnectivityConstraintTest times out.",
+ names: [
+ "android.jobscheduler.cts.TimingConstraintsTest#testJobParameters_unexpiredDeadline"
+ ],
+ bug: 23144425
+},
+{
+ description: "Telephony returning wrong value.",
+ names: [
+ "android.telephony.cts.CellInfoTest#testCellInfo"
+ ],
+ bug: 23979591
+},
+{
+ description: "Video encoding tests are timing out.",
+ names: [
+ "android.media.cts.VideoEncoderTest#testGoogH264FlexArbitraryW",
+ "android.media.cts.VideoEncoderTest#testGoogH264SurfArbitraryW"
+ ],
+ bug: 23827982
+},
+{
+ description: "tests not yet ready",
+ names: [
+ "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneFalse_SpeakerphoneOffInCall",
+ "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault"
+ ],
+ bug: 24067587
+},
+{
+ description: "protected broadcast not working",
+ names: [
+ "android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
+ ],
+ bug: 23192492
}
]
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
index a86a707..241535e 100644
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
+++ b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
@@ -16,6 +16,7 @@
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.cts.jank.leanback.IntentKeys;
import android.os.SystemClock;
import android.support.test.jank.GfxMonitor;
@@ -40,9 +41,30 @@
private final static String JAVA_PACKAGE = "android.cts.jank.leanback.ui";
private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
+ private boolean shouldSkip() {
+ PackageManager packageManager =
+ getInstrumentation().getTargetContext().getPackageManager();
+ if (!packageManager.hasSystemFeature(
+ PackageManager.FEATURE_LEANBACK)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ if (shouldSkip()) {
+ return;
+ }
+ super.runTest();
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
+ if (shouldSkip()) {
+ return;
+ }
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName(APP_PACKAGE, CLASS));
diff --git a/tests/tests/netlegacy22/api/Android.mk b/tests/netlegacy22.api/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/api/Android.mk
rename to tests/netlegacy22.api/Android.mk
diff --git a/tests/tests/netlegacy22/api/AndroidManifest.xml b/tests/netlegacy22.api/AndroidManifest.xml
similarity index 92%
rename from tests/tests/netlegacy22/api/AndroidManifest.xml
rename to tests/netlegacy22.api/AndroidManifest.xml
index d243e45..f13805c 100644
--- a/tests/tests/netlegacy22/api/AndroidManifest.xml
+++ b/tests/netlegacy22.api/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.net.legacy22">
+ package="com.android.cts.netlegacy22.api">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -30,7 +30,7 @@
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.net.legacy22"
+ android:targetPackage="com.android.cts.netlegacy22.api"
android:label="CTS tests of legacy android.net APIs as of API 22">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
similarity index 84%
rename from tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
rename to tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
index 8a9002b..1836f06 100644
--- a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
+++ b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -85,24 +85,58 @@
((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
}
- private void checkSourceAddress(String addrString, int type) throws Exception {
- DatagramSocket d = new DatagramSocket();
- d.connect(InetAddress.getByName(addrString), 7);
- InetAddress localAddress = d.getLocalAddress();
-
+ // Returns a list of all the IP addresses for all the networks of a given legacy type. We can't
+ // just fetch the IP addresses for that type because there is no public getLinkProperties API
+ // that takes a legacy type.
+ private List<InetAddress> getIpAddresses(int type) {
+ ArrayList<InetAddress> addresses = new ArrayList<>();
Network[] networks = mCm.getAllNetworks();
for (int i = 0; i < networks.length; i++) {
NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
if (ni != null && ni.getType() == type) {
+ // This does not include IP addresses on stacked interfaces (e.g., 464xlat), because
+ // there is no public API that will return them.
LinkProperties lp = mCm.getLinkProperties(networks[i]);
for (LinkAddress address : lp.getLinkAddresses()) {
- if (address.getAddress().equals(localAddress)) {
- return;
- }
+ addresses.add(address.getAddress());
}
}
}
- fail("Local address " + localAddress + " not assigned to any network of type " + type);
+ return addresses;
+ }
+
+ private boolean hasIPv4(int type) {
+ for (InetAddress address : getIpAddresses(type)) {
+ if (address instanceof Inet4Address) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void checkSourceAddress(String addrString, int type) throws Exception {
+ // The public requestRouteToHost API only supports IPv4, but it will not return failure if
+ // the network does not have an IPv4 address. So don't check that it's working unless we
+ // know that the network has an IPv4 address. Note that it's possible that the network will
+ // have an IPv4 address but we don't know about it, because the IPv4 address might be on a
+ // stacked interface and we wouldn't be able to see it.
+ if (!hasIPv4(type)) {
+ Log.d(TAG, "Not checking source address on network type " + type + ", no IPv4 address");
+ return;
+ }
+
+ DatagramSocket d = new DatagramSocket();
+ d.connect(InetAddress.getByName(addrString), 7);
+ InetAddress localAddress = d.getLocalAddress();
+ String localAddrString = localAddress.getHostAddress();
+
+ Log.d(TAG, "Got source address " + localAddrString + " for destination " + addrString);
+
+ assertTrue(
+ "Local address " + localAddress + " not assigned to any network of type " + type,
+ getIpAddresses(type).contains(localAddress));
+
+ Log.d(TAG, "Source address " + localAddress + " found on network type " + type);
}
/** Test that hipri can be brought up when Wifi is enabled. */
@@ -127,7 +161,6 @@
assertTrue("Couldn't requestRouteToHost using HIPRI.",
mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
- try { Thread.sleep(1000); } catch(Exception e) {}
checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
diff --git a/tests/tests/netlegacy22/permission/Android.mk b/tests/netlegacy22.permission/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/permission/Android.mk
rename to tests/netlegacy22.permission/Android.mk
diff --git a/tests/tests/netlegacy22/permission/AndroidManifest.xml b/tests/netlegacy22.permission/AndroidManifest.xml
similarity index 89%
rename from tests/tests/netlegacy22/permission/AndroidManifest.xml
rename to tests/netlegacy22.permission/AndroidManifest.xml
index d407404..cd1d2ba 100644
--- a/tests/tests/netlegacy22/permission/AndroidManifest.xml
+++ b/tests/netlegacy22.permission/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.permission">
+ package="com.android.cts.netlegacy22.permission">
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<application>
@@ -41,8 +41,8 @@
relies on hidden APIs.
-->
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.permission"
- android:label="CTS tests of com.android.cts.permission">
+ android:targetPackage="com.android.cts.netlegacy22.permission"
+ android:label="CTS tests of legacy android.net permissions as of API 22">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index ca20549..f5b29cf 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -332,6 +332,9 @@
.setTicker(message)
.setContentTitle("")
.setContentText("")
+ // Mark the notification as "interruptive" by specifying a vibration pattern. This
+ // ensures it's announced properly on watch-type devices.
+ .setVibrate(new long[] {})
.build();
// create and populate the expected event
diff --git a/tests/tests/alarmclock/AndroidTest.xml b/tests/tests/alarmclock/AndroidTest.xml
index 1cdd7f4..aafdb61 100644
--- a/tests/tests/alarmclock/AndroidTest.xml
+++ b/tests/tests/alarmclock/AndroidTest.xml
@@ -17,7 +17,5 @@
<option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
<option name="run-command:run-command"
value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
- <option name="run-command:teardown-command"
- value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
<option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
</configuration>
diff --git a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
index 0089e69..f41100a 100644
--- a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
+++ b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
@@ -23,6 +23,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.AlarmClock;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
@@ -53,23 +55,61 @@
@Override
protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mActivityDoneReceiver);
+ if (mActivityDoneReceiver != null) {
+ try {
+ mContext.unregisterReceiver(mActivityDoneReceiver);
+ } catch (IllegalArgumentException e) {
+ // This exception is thrown if mActivityDoneReceiver in
+ // the above call to unregisterReceiver is never registered.
+ // If so, no harm done by ignoring this exception.
+ }
+ mActivityDoneReceiver = null;
+ }
super.tearDown();
}
private void registerBroadcastReceiver(TestcaseType testCaseType) throws Exception {
mTestCaseType = testCaseType;
mLatch = new CountDownLatch(1);
- if (mActivityDoneReceiver != null) {
- mContext.unregisterReceiver(mActivityDoneReceiver);
- }
mActivityDoneReceiver = new ActivityDoneReceiver();
mContext.registerReceiver(mActivityDoneReceiver,
new IntentFilter(Utils.BROADCAST_INTENT + testCaseType.toString()));
}
+ private boolean isIntentSupported(TestcaseType testCaseType) {
+ Intent intent;
+ switch (testCaseType) {
+ case DISMISS_ALARM:
+ intent = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
+ break;
+
+ case SET_ALARM:
+ case SET_ALARM_FOR_DISMISSAL:
+ intent = new Intent(AlarmClock.ACTION_SET_ALARM);
+ break;
+
+ case SNOOZE_ALARM:
+ intent = new Intent(AlarmClock.ACTION_SNOOZE_ALARM);
+ break;
+
+ default:
+ // shouldn't happen
+ return false;
+ }
+ final PackageManager manager = mContext.getPackageManager();
+ assertNotNull(manager);
+ if (manager.resolveActivity(intent, 0) == null) {
+ Log.i(TAG, "No Voice Activity found for the intent: " + intent.getAction());
+ return false;
+ }
+ return true;
+ }
+
protected String runTest(TestcaseType testCaseType) throws Exception {
Log.i(TAG, "Begin Testing: " + testCaseType);
+ // Make sure the corresponding intent is supported by the platform, before testing.
+ if (!isIntentSupported(testCaseType)) return Utils.COMPLETION_RESULT;
+
if (!startTestActivity(testCaseType)) {
fail("test activity start failed for testcase = " + testCaseType);
return "";
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index b6fef4a..bd96d76 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -20,6 +20,7 @@
import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStats;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -39,7 +40,7 @@
import java.net.URL;
import java.text.MessageFormat;
import java.util.Scanner;
-import javax.net.ssl.HttpsURLConnection;
+import java.net.HttpURLConnection;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -50,20 +51,67 @@
private static final String APPOPS_GET_SHELL_COMMAND = "appops get {0} {1}";
private static final long MINUTE = 1000 * 60;
+ private static final int TIMEOUT_MILLIS = 15000;
- private static final int[] sNetworkTypesToTest = new int[] {
- ConnectivityManager.TYPE_WIFI,
- ConnectivityManager.TYPE_MOBILE,
- };
+ private interface NetworkInterfaceToTest {
+ int getNetworkType();
+ int getTransportType();
+ String getSystemFeature();
+ String getErrorMessage();
+ }
- // Order corresponds to sNetworkTypesToTest
- private static final int[] sTransportTypesToTest = new int[] {
- NetworkCapabilities.TRANSPORT_WIFI,
- NetworkCapabilities.TRANSPORT_CELLULAR,
+ private static final NetworkInterfaceToTest[] sNetworkInterfacesToTest =
+ new NetworkInterfaceToTest[] {
+ new NetworkInterfaceToTest() {
+ @Override
+ public int getNetworkType() {
+ return ConnectivityManager.TYPE_WIFI;
+ }
+
+ @Override
+ public int getTransportType() {
+ return NetworkCapabilities.TRANSPORT_WIFI;
+ }
+
+ @Override
+ public String getSystemFeature() {
+ return PackageManager.FEATURE_WIFI;
+ }
+
+ @Override
+ public String getErrorMessage() {
+ return " Please make sure you are connected to a WiFi access point.";
+ }
+ },
+ new NetworkInterfaceToTest() {
+ @Override
+ public int getNetworkType() {
+ return ConnectivityManager.TYPE_MOBILE;
+ }
+
+ @Override
+ public int getTransportType() {
+ return NetworkCapabilities.TRANSPORT_CELLULAR;
+ }
+
+ @Override
+ public String getSystemFeature() {
+ return PackageManager.FEATURE_TELEPHONY;
+ }
+
+ @Override
+ public String getErrorMessage() {
+ return " Please make sure you have added a SIM card with data plan to" +
+ " your phone, have enabled data over cellular and in case of" +
+ " dual SIM devices, have selected the right SIM " +
+ "for data connection.";
+ }
+ }
};
private NetworkStatsManager mNsm;
private ConnectivityManager mCm;
+ private PackageManager mPm;
private long mStartTime;
private long mEndTime;
@@ -71,62 +119,49 @@
private String mWriteSettingsMode;
private String mUsageStatsMode;
- private void exerciseRemoteHost(int transportType) throws Exception {
- final int timeout = 15000;
- mCm.requestNetwork(new NetworkRequest.Builder()
- .addTransportType(transportType)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build(), new ConnectivityManager.NetworkCallback() {
- @Override
- public void onAvailable(Network network) {
- NetworkInfo networkInfo = mCm.getNetworkInfo(network);
- if (networkInfo == null) {
- Log.w(LOG_TAG, "Network info is null");
- } else {
- Log.w(LOG_TAG, "Network: " + networkInfo.toString());
- }
- InputStreamReader in = null;
- HttpsURLConnection urlc = null;
- String originalKeepAlive = System.getProperty("http.keepAlive");
- System.setProperty("http.keepAlive", "false");
- try {
- urlc = (HttpsURLConnection) network.openConnection(new URL(
- "https://www.google.com"));
- urlc.setConnectTimeout(timeout);
- urlc.setUseCaches(false);
- urlc.connect();
- boolean ping = urlc.getResponseCode() == 200;
- if (ping) {
- in = new InputStreamReader(
- (InputStream) urlc.getContent());
-
- mBytesRead = 0;
- while (in.read() != -1) ++mBytesRead;
- }
- } catch (Exception e) {
- Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // don't care
- }
- }
- if (urlc != null) {
- urlc.disconnect();
- }
- if (originalKeepAlive == null) {
- System.clearProperty("http.keepAlive");
- } else {
- System.setProperty("http.keepAlive", originalKeepAlive);
- }
- }
- }
- });
+ private void exerciseRemoteHost(Network network) throws Exception {
+ NetworkInfo networkInfo = mCm.getNetworkInfo(network);
+ if (networkInfo == null) {
+ Log.w(LOG_TAG, "Network info is null");
+ } else {
+ Log.w(LOG_TAG, "Network: " + networkInfo.toString());
+ }
+ InputStreamReader in = null;
+ HttpURLConnection urlc = null;
+ String originalKeepAlive = System.getProperty("http.keepAlive");
+ System.setProperty("http.keepAlive", "false");
try {
- Thread.sleep(timeout);
- } catch (InterruptedException e) {
+ urlc = (HttpURLConnection) network.openConnection(new URL(
+ "http://www.265.com/"));
+ urlc.setConnectTimeout(TIMEOUT_MILLIS);
+ urlc.setUseCaches(false);
+ urlc.connect();
+ boolean ping = urlc.getResponseCode() == 200;
+ if (ping) {
+ in = new InputStreamReader(
+ (InputStream) urlc.getContent());
+
+ mBytesRead = 0;
+ while (in.read() != -1) ++mBytesRead;
+ }
+ } catch (Exception e) {
+ Log.i(LOG_TAG, "Badness during exercising remote server: " + e);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // don't care
+ }
+ }
+ if (urlc != null) {
+ urlc.disconnect();
+ }
+ if (originalKeepAlive == null) {
+ System.clearProperty("http.keepAlive");
+ } else {
+ System.setProperty("http.keepAlive", originalKeepAlive);
+ }
}
}
@@ -139,6 +174,8 @@
mCm = (ConnectivityManager) getInstrumentation().getContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mPm = getInstrumentation().getContext().getPackageManager();
+
mWriteSettingsMode = getAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS);
setAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS, "allow");
mUsageStatsMode = getAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS);
@@ -190,19 +227,65 @@
}
}
- private boolean shouldTestThisNetworkType(int networkTypeIndex, long tolerance)
- throws Exception {
- NetworkInfo networkInfo = mCm.getNetworkInfo(sNetworkTypesToTest[networkTypeIndex]);
- if (networkInfo == null || !networkInfo.isAvailable()) {
- return false;
+ private class NetworkCallback extends ConnectivityManager.NetworkCallback {
+ private long mTolerance;
+ public boolean success;
+
+ NetworkCallback(long tolerance) {
+ mTolerance = tolerance;
+ success = false;
}
- mStartTime = System.currentTimeMillis() - tolerance;
- exerciseRemoteHost(sTransportTypesToTest[networkTypeIndex]);
- mEndTime = System.currentTimeMillis() + tolerance;
- return true;
+
+ @Override
+ public void onAvailable(Network network) {
+ try {
+ mStartTime = System.currentTimeMillis() - mTolerance;
+ exerciseRemoteHost(network);
+ mEndTime = System.currentTimeMillis() + mTolerance;
+ success = true;
+ synchronized(NetworkUsageStatsTest.this) {
+ NetworkUsageStatsTest.this.notify();
+ }
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "exercising remote host failed.", e);
+ success = false;
+ }
+ }
}
- private String getSubscriberId(int networkType) {
+ private boolean shouldTestThisNetworkType(int networkTypeIndex, final long tolerance)
+ throws Exception {
+ boolean hasFeature = mPm.hasSystemFeature(
+ sNetworkInterfacesToTest[networkTypeIndex].getSystemFeature());
+ if (!hasFeature) {
+ return false;
+ }
+ NetworkCallback callback = new NetworkCallback(tolerance);
+ mCm.requestNetwork(new NetworkRequest.Builder()
+ .addTransportType(sNetworkInterfacesToTest[networkTypeIndex].getTransportType())
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build(), callback);
+ synchronized(this) {
+ try {
+ wait((int)(TIMEOUT_MILLIS * 1.2));
+ } catch (InterruptedException e) {
+ }
+ }
+ if (callback.success) {
+ return true;
+ }
+
+ // This will always fail at this point as we know 'hasFeature' is true.
+ assertFalse (sNetworkInterfacesToTest[networkTypeIndex].getSystemFeature() +
+ " is a reported system feature, " +
+ "however no corresponding connected network interface was found or the attempt " +
+ "to connect has timed out (timeout = " + TIMEOUT_MILLIS + "ms)." +
+ sNetworkInterfacesToTest[networkTypeIndex].getErrorMessage(), hasFeature);
+ return false;
+ }
+
+ private String getSubscriberId(int networkIndex) {
+ int networkType = sNetworkInterfacesToTest[networkIndex].getNetworkType();
if (ConnectivityManager.TYPE_MOBILE == networkType) {
TelephonyManager tm = (TelephonyManager) getInstrumentation().getContext()
.getSystemService(Context.TELEPHONY_SERVICE);
@@ -212,7 +295,7 @@
}
public void testDeviceSummary() throws Exception {
- for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
if (!shouldTestThisNetworkType(i, MINUTE/2)) {
continue;
}
@@ -220,7 +303,7 @@
NetworkStats.Bucket bucket = null;
try {
bucket = mNsm.querySummaryForDevice(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
} catch (RemoteException | SecurityException e) {
fail("testDeviceSummary fails with exception: " + e.toString());
@@ -232,7 +315,7 @@
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
try {
bucket = mNsm.querySummaryForDevice(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
fail("negative testDeviceSummary fails: no exception thrown.");
} catch (RemoteException e) {
@@ -244,7 +327,7 @@
}
public void testUserSummary() throws Exception {
- for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
if (!shouldTestThisNetworkType(i, MINUTE/2)) {
continue;
}
@@ -252,7 +335,7 @@
NetworkStats.Bucket bucket = null;
try {
bucket = mNsm.querySummaryForUser(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
} catch (RemoteException | SecurityException e) {
fail("testUserSummary fails with exception: " + e.toString());
@@ -264,7 +347,7 @@
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
try {
bucket = mNsm.querySummaryForUser(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
fail("negative testUserSummary fails: no exception thrown.");
} catch (RemoteException e) {
@@ -276,7 +359,7 @@
}
public void testAppSummary() throws Exception {
- for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
if (!shouldTestThisNetworkType(i, MINUTE/2)) {
continue;
}
@@ -284,7 +367,7 @@
NetworkStats result = null;
try {
result = mNsm.querySummary(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
assertTrue(result != null);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -317,7 +400,7 @@
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
try {
result = mNsm.querySummary(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
fail("negative testAppSummary fails: no exception thrown.");
} catch (RemoteException e) {
@@ -329,7 +412,7 @@
}
public void testAppDetails() throws Exception {
- for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
// Relatively large tolerance to accommodate for history bucket size.
if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
continue;
@@ -338,7 +421,7 @@
NetworkStats result = null;
try {
result = mNsm.queryDetails(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
assertTrue(result != null);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -372,7 +455,7 @@
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
try {
result = mNsm.queryDetails(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime);
fail("negative testAppDetails fails: no exception thrown.");
} catch (RemoteException e) {
@@ -384,7 +467,7 @@
}
public void testUidDetails() throws Exception {
- for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
+ for (int i = 0; i < sNetworkInterfacesToTest.length; ++i) {
// Relatively large tolerance to accommodate for history bucket size.
if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
continue;
@@ -393,7 +476,7 @@
NetworkStats result = null;
try {
result = mNsm.queryDetailsForUid(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime, Process.myUid());
assertTrue(result != null);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -426,7 +509,7 @@
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
try {
result = mNsm.queryDetailsForUid(
- sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+ sNetworkInterfacesToTest[i].getNetworkType(), getSubscriberId(i),
mStartTime, mEndTime, Process.myUid());
fail("negative testUidDetails fails: no exception thrown.");
} catch (RemoteException e) {
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index dfa278a..c8ef253 100644
--- a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
@@ -40,6 +41,8 @@
}
public static class ExpectedMemorySizesClass {
+ private static final Map<Integer, Integer> expectedMemorySizeForWatch
+ = new HashMap<Integer, Integer>();
private static final Map<Integer, Integer> expectedMemorySizeForSmallNormalScreen
= new HashMap<Integer, Integer>();
private static final Map<Integer, Integer> expectedMemorySizeForLargeScreen
@@ -48,6 +51,21 @@
= new HashMap<Integer, Integer>();
static {
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_LOW, 32);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_MEDIUM, 32);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_TV, 32);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_HIGH, 36);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_280, 36);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XHIGH, 48);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112);
+ expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154);
+ }
+
+ static {
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_LOW, 32);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_MEDIUM, 32);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48);
@@ -92,7 +110,15 @@
expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
}
- public static Integer getExpectedMemorySize(int screenSize, int screenDensity) {
+ public static Integer getExpectedMemorySize(
+ int screenSize,
+ int screenDensity,
+ boolean isWatch) {
+
+ if (isWatch) {
+ return expectedMemorySizeForWatch.get(screenDensity);
+ }
+
switch (screenSize) {
case Configuration.SCREENLAYOUT_SIZE_SMALL:
case Configuration.SCREENLAYOUT_SIZE_NORMAL:
@@ -141,8 +167,11 @@
}
private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) {
- int expectedMinimumMemory = ExpectedMemorySizesClass.getExpectedMemorySize(screenSize,
- screenDensity);
+ Context context = getInstrumentation().getTargetContext();
+ boolean isWatch =
+ context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ int expectedMinimumMemory =
+ ExpectedMemorySizesClass.getExpectedMemorySize(screenSize, screenDensity, isWatch);
assertTrue("Expected to have at least " + expectedMinimumMemory
+ "mb of memory for screen density " + screenDensity,
diff --git a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
index 5781442..fbb3060 100644
--- a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -74,9 +74,8 @@
sendNotification(id, R.drawable.black);
mNotificationManager.cancel(id);
- StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
- for (StatusBarNotification sbn : sbns) {
- assertFalse("canceled notification was still alive, id=" + id, sbn.getId() == id);
+ if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
+ fail("canceled notification was still alive, id=" + id);
}
}
@@ -116,10 +115,31 @@
.build();
mNotificationManager.notify(id, notification);
- StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
- for (StatusBarNotification sbn : sbns) {
- if (sbn.getId() == id) return;
+
+ if (!checkNotificationExistence(id, /*shouldExist=*/ true)) {
+ fail("couldn't find posted notification id=" + id);
}
- fail("couldn't find posted notification id=" + id);
+ }
+
+ private boolean checkNotificationExistence(int id, boolean shouldExist) {
+ // notification is a bit asynchronous so it may take a few ms to appear in getActiveNotifications()
+ // we will check for it for up to 200ms before giving up
+ boolean found = false;
+ for (int tries=3; tries-->0;) {
+ final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+ for (StatusBarNotification sbn : sbns) {
+ if (sbn.getId() == id) {
+ found = true;
+ break;
+ }
+ }
+ if (found == shouldExist) break;
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ // pass
+ }
+ }
+ return found == shouldExist;
}
}
diff --git a/tests/tests/assist/AndroidManifest.xml b/tests/tests/assist/AndroidManifest.xml
index fefdf54..a81ced2 100644
--- a/tests/tests/assist/AndroidManifest.xml
+++ b/tests/tests/assist/AndroidManifest.xml
@@ -20,17 +20,22 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
+ <uses-permission android:name="android.permission.INTERNET" />
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.assist.cts.TestStartActivity"
- android:label="Assist Structure Test App"
- android:theme="@android:style/Theme.Material.Light">
+ android:label="Assist Test Start Activity">
<intent-filter>
<action android:name="android.intent.action.TEST_START_ACTIVITY_ASSIST_STRUCTURE" />
<action android:name="android.intent.action.TEST_START_ACTIVITY_DISABLE_CONTEXT" />
<action android:name="android.intent.action.TEST_START_ACTIVITY_FLAG_SECURE" />
<action android:name="android.intent.action.TEST_START_ACTIVITY_LIFECYCLE" />
+ <action android:name="android.intent.action.TEST_START_ACTIVITY_SCREENSHOT" />
+ <action android:name="android.intent.action.TEST_START_ACTIVITY_EXTRA_ASSIST" />
+ <action android:name="android.intent.action.TEST_START_ACTIVITY_TEXTVIEW" />
+ <action android:name="android.intent.action.TEST_START_ACTIVITY_LARGE_VIEW_HIERARCHY" />
+ <action android:name="android.intent.action.TEST_START_ACTIVITY_WEBVIEW" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index f7c56ad..329692d 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -19,7 +19,5 @@
<option name="cts-apk-installer:test-file-name" value="CtsAssistApp.apk" />
<option name="run-command:run-command"
value="settings put secure voice_interaction_service android.assist.service/.MainInteractionService" />
- <option name="run-command:teardown-command"
- value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
<option name="cts-apk-installer:test-file-name" value="CtsAssistTestCases.apk" />
</configuration>
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index 4bf9412..54416b4 100644
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -19,6 +19,8 @@
import android.content.ComponentName;
import android.os.Bundle;
+import org.json.JSONException;
+import org.json.JSONObject;
import java.util.ArrayList;
public class Utils {
@@ -29,13 +31,24 @@
public static final String BROADCAST_ASSIST_DATA_INTENT = ACTION_PREFIX + "ASSIST_DATA";
public static final String BROADCAST_INTENT_START_ASSIST = ACTION_PREFIX + "START_ASSIST";
public static final String ASSIST_RECEIVER_REGISTERED = ACTION_PREFIX + "ASSIST_READY";
+
+ public static final String ACTION_INVALIDATE = "invalidate_action";
+ public static final String GET_CONTENT_VIEW_HEIGHT = ACTION_PREFIX + "GET_CONTENT_VIEW_HEIGHT";
+ public static final String BROADCAST_CONTENT_VIEW_HEIGHT = ACTION_PREFIX + "VIEW_HEIGHT";
+ public static final String SCROLL_TEXTVIEW_ACTION = ACTION_PREFIX + "TEXTVIEW_SCROLL";
+ public static final String SCROLL_SCROLLVIEW_ACTION = ACTION_PREFIX + "SCROLLVIEW_SCROLL";
public static final String TEST_ERROR = "Error In Test:";
public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
public static final String ASSIST_CONTENT_KEY = "assist_content";
public static final String ASSIST_BUNDLE_KEY = "assist_bundle";
public static final String ASSIST_SCREENSHOT_KEY = "assist_screenshot";
-
+ public static final String SCREENSHOT_COLOR_KEY = "set_screenshot_color";
+ public static final String COMPARE_SCREENSHOT_KEY = "compare_screenshot";
+ public static final String DISPLAY_WIDTH_KEY = "display_width";
+ public static final String DISPLAY_HEIGHT_KEY = "dislay_height";
+ public static final String SCROLL_X_POSITION = "scroll_x_position";
+ public static final String SCROLL_Y_POSITION = "scroll_y_position";
/** Lifecycle Test intent constants */
public static final String LIFECYCLE_PREFIX = ACTION_PREFIX + "lifecycle_";
@@ -44,35 +57,103 @@
public static final String LIFECYCLE_ONSTOP = LIFECYCLE_PREFIX + "onstop";
public static final String LIFECYCLE_ONDESTROY = LIFECYCLE_PREFIX + "ondestroy";
+ /** Focus Change Test intent constants */
+ public static final String GAINED_FOCUS = ACTION_PREFIX + "focus_changed";
+ public static final String LOST_FOCUS = ACTION_PREFIX + "lost_focus";
+
/** Flag Secure Test intent constants */
public static final String FLAG_SECURE_HASRESUMED = ACTION_PREFIX + "flag_secure_hasResumed";
- public static final String ASSIST_STRUCTURE_HASRESUMED = ACTION_PREFIX
- + "assist_structure_hasResumed";
+ public static final String APP_3P_HASRESUMED = ACTION_PREFIX + "app_3p_hasResumed";
+ public static final String TEST_ACTIVITY_LOADED = ACTION_PREFIX + "test_activity_hasResumed";
/** Two second timeout for getting back assist context */
public static final int TIMEOUT_MS = 2 * 1000;
+ /** Four second timeout for an activity to resume */
public static final int ACTIVITY_ONRESUME_TIMEOUT_MS = 4000;
+
public static final String EXTRA_REGISTER_RECEIVER = "register_receiver";
+ /** Extras for passing the Assistant's ContentView's dimensions*/
+ public static final String EXTRA_CONTENT_VIEW_HEIGHT = "extra_content_view_height";
+ public static final String EXTRA_CONTENT_VIEW_WIDTH = "extra_content_view_width";
+ public static final String EXTRA_DISPLAY_POINT = "extra_display_point";
+
/** Test name suffixes */
public static final String ASSIST_STRUCTURE = "ASSIST_STRUCTURE";
public static final String DISABLE_CONTEXT = "DISABLE_CONTEXT";
public static final String FLAG_SECURE = "FLAG_SECURE";
public static final String LIFECYCLE = "LIFECYCLE";
+ public static final String SCREENSHOT = "SCREENSHOT";
+ public static final String EXTRA_ASSIST = "EXTRA_ASSIST";
+ public static final String VERIFY_CONTENT_VIEW = "VERIFY_CONTENT_VIEW";
+ public static final String TEXTVIEW = "TEXTVIEW";
+ public static final String LARGE_VIEW_HIERARCHY = "LARGE_VIEW_HIERARCHY";
+ public static final String WEBVIEW = "WEBVIEW";
+ public static final String FOCUS_CHANGE = "FOCUS_CHANGE";
/** Session intent constants */
public static final String HIDE_SESSION = "android.intent.action.hide_session";
- /**
- * The shim activity that starts the service associated with each test.
- */
+ /** Stub html view to load into WebView */
+ public static final String WEBVIEW_HTML_GREETING = "Hello WebView!";
+ public static final String WEBVIEW_HTML = "<html><body><div><p>" + WEBVIEW_HTML_GREETING
+ + "</p></div></body></html>";
+
+ /** Extra data to add to assist data and assist content */
+ private static Bundle EXTRA_ASSIST_BUNDLE;
+ private static String STRUCTURED_JSON;
+
+ public static final String getStructuredJSON() throws Exception {
+ if (STRUCTURED_JSON == null) {
+ STRUCTURED_JSON = new JSONObject()
+ .put("@type", "MusicRecording")
+ .put("@id", "https://example/music/recording")
+ .put("url", "android-app://com.example/https/music/album")
+ .put("name", "Album Title")
+ .put("hello", "hi there")
+ .put("knownNull", null)
+ .put("unicode value", "\ud800\udc35")
+ .put("empty string", "")
+ .put("LongString",
+ "lkasdjfalsdkfjalsdjfalskj9i9234jl1w23j4o123j412l3j421l3kj412l3kj1l3k4j32")
+ .put("\ud800\udc35", "any-value")
+ .put("key with spaces", "any-value")
+ .toString();
+ }
+ return STRUCTURED_JSON;
+ }
+
+ public static final Bundle getExtraAssistBundle() {
+ if (EXTRA_ASSIST_BUNDLE == null) {
+ EXTRA_ASSIST_BUNDLE = new Bundle();
+ addExtraAssistDataToBundle(EXTRA_ASSIST_BUNDLE);
+ }
+ return EXTRA_ASSIST_BUNDLE;
+ }
+
+ public static void addExtraAssistDataToBundle(Bundle data) {
+ data.putString("hello", "there");
+ data.putBoolean("isthis_true_or_false", true);
+ data.putInt("number", 123);
+ }
+
+ /** The shim activity that starts the service associated with each test. */
public static final String getTestActivity(String testCaseType) {
switch (testCaseType) {
case DISABLE_CONTEXT:
+ // doesn't need to wait for activity to resume
+ // can be activated on top of any non-secure activity.
return "service.DisableContextActivity";
case ASSIST_STRUCTURE:
case FLAG_SECURE:
case LIFECYCLE:
+ case SCREENSHOT:
+ case EXTRA_ASSIST:
+ case VERIFY_CONTENT_VIEW:
+ case TEXTVIEW:
+ case LARGE_VIEW_HIERARCHY:
+ case WEBVIEW:
+ case FOCUS_CHANGE:
return "service.DelayedAssistantActivity";
default:
return "";
@@ -85,22 +166,51 @@
public static final ComponentName getTestAppComponent(String testCaseType) {
switch (testCaseType) {
case ASSIST_STRUCTURE:
+ case LARGE_VIEW_HIERARCHY:
return new ComponentName(
"android.assist.testapp", "android.assist.testapp.TestApp");
case DISABLE_CONTEXT:
return new ComponentName(
- "android.assist.testapp", "android.assist.testapp.DisableContextActivity");
+ "android.assist.testapp", "android.assist.testapp.TestApp");
case FLAG_SECURE:
return new ComponentName(
"android.assist.testapp", "android.assist.testapp.SecureActivity");
case LIFECYCLE:
return new ComponentName(
"android.assist.testapp", "android.assist.testapp.LifecycleActivity");
+ case SCREENSHOT:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.ScreenshotActivity");
+ case EXTRA_ASSIST:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.ExtraAssistDataActivity");
+ case TEXTVIEW:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.TextViewActivity");
+ case WEBVIEW:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.WebViewActivity");
+ case FOCUS_CHANGE:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.FocusChangeActivity");
default:
return new ComponentName("","");
}
}
+ /**
+ * Returns the amount of time to wait for assist data.
+ */
+ public static final int getAssistDataTimeout(String testCaseType) {
+ switch (testCaseType) {
+ case SCREENSHOT:
+ // needs to wait for 3p activity to resume before receiving assist data.
+ return TIMEOUT_MS + ACTIVITY_ONRESUME_TIMEOUT_MS;
+ default:
+ return TIMEOUT_MS;
+ }
+ }
+
public static final String toBundleString(Bundle bundle) {
if (bundle == null) {
return "*** Bundle is null ****";
diff --git a/tests/tests/assist/res/layout/multiple_text_views.xml b/tests/tests/assist/res/layout/multiple_text_views.xml
new file mode 100644
index 0000000..455d5e3
--- /dev/null
+++ b/tests/tests/assist/res/layout/multiple_text_views.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+ </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/screenshot_activity.xml b/tests/tests/assist/res/layout/screenshot_activity.xml
new file mode 100644
index 0000000..05051dc
--- /dev/null
+++ b/tests/tests/assist/res/layout/screenshot_activity.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/screenshot_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/text_view.xml b/tests/tests/assist/res/layout/text_view.xml
new file mode 100644
index 0000000..9964ab6
--- /dev/null
+++ b/tests/tests/assist/res/layout/text_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:focusable="false"
+ android:focusableInTouchMode="false"
+ android:scrollbars="vertical"
+ android:clickable="true"
+ android:text="@string/text_too_large_to_fit" />
+
+ <ScrollView
+ android:id="@+id/scroll_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+ </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/layout/webview.xml b/tests/tests/assist/res/layout/webview.xml
new file mode 100644
index 0000000..bdb8082
--- /dev/null
+++ b/tests/tests/assist/res/layout/webview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <WebView
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </WebView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/res/values/strings.xml b/tests/tests/assist/res/values/strings.xml
index ae4f16e..8170d70 100644
--- a/tests/tests/assist/res/values/strings.xml
+++ b/tests/tests/assist/res/values/strings.xml
@@ -15,4 +15,270 @@
-->
<resources>
<string name="welcome">Hello there!</string>
+ <string name="testAppTitle">Assist Structure Test Activity</string>
+ <string name="screenshotActivityTitle">Screenshot Test Activity</string>
+ <string name="textViewActivityTitle">TextView Test Activity</string>
+ <string name="webViewActivityTitle">WebView Test Activity</string>
+ <string name="text_too_large_to_fit">❤ ☀ ☆ ☂ ☻ ♞ ☯ ☭ ☢ € →Hello هتاف للترحيب שלום
+ përshëndetje Добры дзень 您好 হ্যালো здравей მიესალმები Χαίρετε હેલો नमस्ते Nnọọ こんにちは ಹಲೋ
+ Сәлеметсіз бе ជំរាបសួរ 안녕하세요 ສະບາຍດີ ഹലോ हॅलो Сайн байна уу नमस्ते سلامהעלא ہیلو
+ မင်္ဂလာပါ ਸਤ ਸ੍ਰੀ ਅਕਾਲ Здравствуйте здраво ආයුබෝවන් ஹலோ హలో สวัสดี Pẹlẹ o
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ convallis nunc et vestibulum. Sed et consequat quam, blandit varius tortor. Curabitur
+ accumsan nulla lectus, placerat condimentum odio elementum vel. Nulla erat ex, accumsan ut
+ enim sagittis, scelerisque efficitur ante. Nullam quis orci nec magna maximus malesuada ac
+ id sem. Nam sagittis erat risus, a accumsan neque congue sit amet. Nullam risus velit,
+ faucibus eget scelerisque et, maximus eget arcu. Sed porta sed libero ac imperdiet.
+
+ Nulla sem lectus, ullamcorper id dui vel, rutrum interdum augue. Proin aliquam nisi vitae
+ hendrerit tempor. Mauris porttitor velit et egestas feugiat. Vivamus eu dapibus libero,
+ quis fringilla urna. Suspendisse non turpis dui. Vivamus facilisis diam vitae est auctor
+ luctus. Etiam quis lectus viverra, interdum turpis eu, aliquam sem. Nulla vulputate lacinia
+ nisi a dictum. Cras faucibus vitae tortor at ullamcorper. Quisque sit amet sapien maximus,
+ ornare nisi non, imperdiet magna. Vestibulum tempor metus ac mi ultrices dapibus.
+
+ Suspendisse potenti. Mauris pellentesque lacinia tristique. Pellentesque vel dui quis sem
+ lacinia imperdiet feugiat vitae sem. Proin a arcu magna. Sed quis augue eu mi accumsan
+ pellentesque pretium in leo. Duis euismod purus mauris, ac tempor erat auctor non. Quisque
+ bibendum est pulvinar ex dapibus, ac tincidunt nibh tempus. Mauris sodales sem id purus
+ commodo iaculis. Pellentesque a quam dapibus, vehicula lectus at, tincidunt arcu. In
+ placerat porttitor urna quis consequat. Nullam feugiat nisl sed urna hendrerit, sed
+ elementum massa iaculis. Fusce sit amet turpis hendrerit, varius lorem sed, luctus mi.
+ Phasellus sit amet ex orci. Duis scelerisque nisl quis efficitur maximus. Curabitur vitae
+ accumsan nunc, eget varius nisi.
+
+ Fusce efficitur malesuada luctus. Aliquam dapibus tortor sit amet purus semper, sit amet
+ pretium lorem feugiat. Maecenas gravida sed arcu et placerat. Nulla facilisi. Cras placerat
+ rutrum mi, in rutrum mauris maximus at. Mauris eu suscipit ante. Nullam pharetra egestas
+ diam a viverra. Donec sem turpis, tempor malesuada est vel, blandit accumsan magna. In
+ iaculis velit in efficitur hendrerit. Nulla facilisi. Curabitur eget ligula lorem. Sed sit
+ amet dolor ut ligula malesuada condimentum. Phasellus molestie augue eget libero commodo,
+ vel blandit ex blandit.
+
+ Morbi cursus tortor ante, et tempus nisi tempus et. Suspendisse quis gravida diam. Aliquam
+ efficitur dolor sit amet sollicitudin varius. Etiam libero purus, ornare nec nulla vel,
+ ullamcorper blandit nisl. Sed vel consequat diam, id placerat sem. Donec quis elementum
+ urna. In posuere bibendum nunc, in condimentum justo blandit ac. Quisque enim lorem,
+ gravida at purus at, sollicitudin imperdiet erat. Ut consectetur rutrum ante, et pretium
+ odio iaculis a. Nullam a nibh vulputate, volutpat lectus eu, pellentesque felis. Nam
+ vehicula suscipit diam nec convallis. Quisque congue maximus sem, sit amet hendrerit leo
+ tempor et.
+
+ Nam eu consequat dui. Sed semper dignissim mattis. Integer tortor eros, tempor in lectus a,
+ lobortis aliquam dolor. Phasellus at sagittis magna. Nulla eleifend orci ac urna auctor,
+ sit amet luctus urna vulputate. Nulla venenatis venenatis erat ac finibus. Etiam
+ ullamcorper elementum suscipit. Morbi nec velit non mauris porta finibus. Nullam in
+ sagittis odio. Praesent eget nisl ut mauris vestibulum feugiat. Sed vulputate at elit et
+ cursus. Praesent viverra erat blandit nunc egestas, vel feugiat ex condimentum. Class
+ aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+
+ Nulla fermentum mattis urna, non gravida eros vestibulum et. Fusce porttitor augue turpis,
+ sit amet aliquam augue sodales non. Nunc neque odio, sagittis sed gravida euismod, commodo
+ at libero. Donec porttitor pulvinar neque vitae lobortis. Aliquam accumsan velit nec sapien
+ placerat egestas. Aliquam at tincidunt massa, et dignissim justo. Donec sapien ante, rutrum
+ et tristique a, commodo a massa.
+
+ Nunc placerat lobortis magna, et molestie lacus semper porta. Lorem ipsum dolor sit amet,
+ consectetur adipiscing elit. Phasellus ac ligula dui. Duis ultrices viverra eros fermentum
+ finibus. Integer ultrices, felis in accumsan volutpat, mi ligula hendrerit nunc, nec
+ accumsan mauris tellus sit amet metus. Ut pharetra enim et sapien sollicitudin, nec
+ ultricies urna pharetra. Morbi non tortor nec dui feugiat rutrum. Aliquam malesuada sodales
+ risus, sed congue nunc accumsan vitae. Etiam nunc magna, tempus non suscipit eu, feugiat ut
+ nibh. Maecenas et libero ut nisl pellentesque tempor nec vel quam. Etiam sem ligula,
+ ullamcorper non dolor a, viverra placerat nulla. Nullam dictum commodo dui, sed ultrices
+ enim sagittis eget. Morbi non consectetur lectus. In gravida, augue vitae pulvinar
+ molestie, ligula orci vulputate ex, at bibendum urna felis nec nibh. Sed nisl nunc, iaculis
+ at augue venenatis, fringilla accumsan velit. Curabitur nec augue porttitor, rutrum nisi
+ vitae, elementum orci.
+
+ Vestibulum eu tortor iaculis, dignissim velit quis, rhoncus dolor. Donec et tincidunt
+ nulla. Duis faucibus auctor erat ac ultricies. In a fermentum mi. Fusce vitae mi id sem
+ interdum tincidunt. Nulla hendrerit orci turpis, in maximus elit mollis eget. Aliquam erat
+ volutpat. Phasellus mattis est nibh, ut scelerisque ligula egestas eu. Ut molestie orci a
+ malesuada tempor. Sed tempus arcu id orci gravida faucibus. Vivamus ac lacinia neque, at
+ vehicula magna.
+
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+ Nullam aliquam, justo scelerisque egestas sodales, purus odio posuere arcu, ac ultrices
+ nunc felis non massa. Aliquam vulputate ipsum sed aliquet auctor. In pulvinar, eros sit
+ amet ultricies tristique, lacus ipsum scelerisque eros, nec vestibulum est lectus quis
+ lorem. Pellentesque ac augue ut eros mattis viverra vitae ut lacus. Phasellus imperdiet
+ efficitur elit eget tincidunt. Donec sodales metus at dolor pulvinar, at gravida nibh
+ facilisis. Sed nec tellus luctus, cursus lacus sed, euismod orci. Maecenas sit amet leo
+ orci. Nulla non leo non mi eleifend consequat sit amet vitae dui. Sed gravida gravida
+ justo, tincidunt ultrices justo semper vitae. Fusce at nisi nisl. Morbi molestie quis justo
+ a convallis. Curabitur massa lacus, feugiat quis mauris ac, malesuada viverra est.
+
+ Phasellus bibendum faucibus velit, ac scelerisque velit tincidunt eu. Curabitur quis
+ suscipit erat, ac feugiat odio. Nullam et sapien et nibh maximus posuere. Vivamus faucibus
+ justo eget dictum sollicitudin. Etiam at leo eget elit facilisis lobortis. Maecenas
+ bibendum tortor non erat pretium dignissim. Fusce id imperdiet augue. Suspendisse dignissim
+ magna vel odio viverra varius. Maecenas suscipit ante et lorem sodales vehicula. Quisque
+ vel magna id sem suscipit iaculis. Etiam in elementum risus.
+
+ Suspendisse odio nisi, pharetra et purus sit amet, placerat lobortis diam. Phasellus enim
+ nunc, posuere sed porta in, ornare eu ipsum. Phasellus imperdiet porta neque, vitae dapibus
+ tellus feugiat eget. Nulla sodales leo ac efficitur luctus. Vivamus eget ipsum quis ante
+ pulvinar blandit. Vestibulum a justo convallis justo elementum viverra ut sit amet nisl.
+ Suspendisse eget augue fermentum, sagittis risus a, rhoncus elit. Vestibulum in maximus
+ tortor, non vestibulum libero. Nunc accumsan neque a nisl dapibus, id laoreet neque congue.
+ Pellentesque sapien odio, fringilla non nulla nec, varius placerat diam. Aliquam
+ consectetur neque eu ipsum posuere, nec dignissim sem faucibus. Donec sit amet tempor
+ sapien. Nam at libero vel lorem dapibus ultrices a vel augue. Nunc facilisis justo ante,
+ mollis tristique velit aliquet quis. Mauris consectetur odio at urna bibendum aliquam.
+
+ Nullam lectus orci, hendrerit ut ultrices in, dapibus pellentesque nibh. Aliquam arcu
+ metus, lobortis vel dignissim id, tempus ut ante. Integer vitae ante augue. In hac habitasse
+ platea dictumst. Vestibulum in tellus ante. Cras nisi tellus, congue ac velit quis, rhoncus
+ ornare ligula. Sed facilisis gravida pellentesque. Praesent id ultrices orci, ac ultricies
+ arcu. Donec at ante quis augue faucibus congue. Donec mattis quam dui, ut vestibulum orci
+ tempor mattis. Phasellus in quam id tortor varius ullamcorper ac ac ante. Proin cursus
+ accumsan sem, vel finibus lectus eleifend ut. Donec efficitur feugiat diam id ultricies. In
+ quis euismod nisi. Vestibulum eget viverra sapien. Donec scelerisque nec elit vel viverra.
+
+ Sed mi urna, rutrum quis augue vel, aliquet placerat diam. Proin faucibus in odio et
+ consequat. Proin ut ex in mauris eleifend efficitur. Praesent ullamcorper sollicitudin urna,
+ sed mollis elit hendrerit non. Duis leo lorem, efficitur eu auctor sit amet, scelerisque
+ scelerisque magna. Mauris eget massa auctor, viverra arcu a, elementum nibh. Sed
+ pellentesque, nulla sed condimentum posuere, tortor metus congue sem, nec placerat neque
+ magna vitae purus.
+
+ Etiam at risus vitae sapien aliquam condimentum. Vestibulum id libero placerat purus
+ vehicula consectetur. Pellentesque sapien sapien, posuere at pulvinar at, ultrices sed est.
+ Maecenas nec condimentum ante. Aenean volutpat, ex condimentum hendrerit hendrerit, quam
+ nisl pharetra nibh, vitae bibendum nisl odio vel lacus. Morbi mi tellus, bibendum id mauris
+ eu, facilisis volutpat turpis. Maecenas rutrum convallis felis. Quisque eget feugiat felis.
+ Duis pellentesque iaculis massa ut facilisis. Donec nec commodo magna. Integer aliquet orci
+ a odio eleifend elementum. Quisque molestie, urna ut molestie eleifend, odio neque maximus
+ enim, eget viverra metus lectus eget quam. Fusce nec urna ac neque bibendum aliquam vel quis
+ dui. Fusce ac quam consequat, feugiat leo vitae, auctor felis.
+
+ Sed ac metus mauris. Sed sed velit ut tortor aliquam vestibulum at eu arcu. Etiam eu
+ posuere lacus. Maecenas id lacus quis sem mollis sodales. Quisque justo sapien, vulputate ac
+ mi ut, congue vestibulum orci. Donec euismod erat rutrum, laoreet urna sed, accumsan purus.
+ Donec eu quam a sapien condimentum accumsan. Sed at tellus lorem. Curabitur bibendum, arcu
+ sit amet finibus sodales, mi sem finibus sem, eget scelerisque tellus neque vel urna.
+ Suspendisse eu augue nec erat suscipit luctus sed non metus.
+
+ Suspendisse porttitor ex ipsum. Pellentesque tristique eros sed pharetra porttitor.
+ Quisque ut elit vehicula, aliquet est nec, faucibus tellus. Donec ex augue, congue eu
+ dignissim maximus, vestibulum at purus. Nulla quam enim, laoreet sit amet molestie vel,
+ dapibus nec tortor. Sed interdum massa ac orci gravida, vel viverra lacus lacinia. Donec
+ nisl lacus, fermentum at faucibus ac, consequat ut nibh. Praesent laoreet est augue, vitae
+ maximus dui efficitur sit amet. Cras ipsum tellus, tincidunt at volutpat non, tincidunt ut
+ elit. Morbi commodo sagittis gravida. Pellentesque sed ante massa. Phasellus a turpis non
+ turpis cursus consequat sed nec tortor. Proin et augue elit.
+
+ Duis finibus sem commodo rutrum pulvinar. In sollicitudin ante magna, vel facilisis
+ tellus fringilla vel. Nam purus ex, tincidunt eget varius at, euismod nec elit. Curabitur
+ consequat nulla vel nisi iaculis, ut mattis odio congue. Nulla et mollis tortor, a maximus
+ justo. Donec semper eros sed nunc rhoncus condimentum. Donec nibh purus, interdum non lectus
+ id, porta convallis eros.
+
+ Sed hendrerit, dui non sagittis sollicitudin, enim ex imperdiet sapien, et maximus lorem
+ dolor a enim. Nulla risus nisl, vestibulum at ornare posuere, congue in felis. Duis sagittis
+ id diam a varius. Donec viverra eu orci sodales commodo. Cras metus tortor, sodales vitae
+ auctor non, scelerisque a ante. Quisque sodales nisi libero, ut lobortis enim suscipit ut.
+ Cras mi ipsum, maximus non bibendum sit amet, pharetra quis ipsum. Vestibulum venenatis, odi
+ at hendrerit pretium, tellus diam auctor justo, non posuere quam mauris id nisl. Nam dolor
+ nibh, molestie et lectus et, scelerisque porta elit. Vestibulum viverra condimentum auctor.
+ In eros tortor, convallis sed quam eu, ultrices malesuada purus. Integer lorem quam,
+ ultricies at est consectetur, sagittis porttitor eros. Proin non risus vitae lacus
+ consectetur malesuada non pulvinar justo. Aliquam mollis nisi nunc, sit amet vulputate metus
+ sollicitudin vel.
+
+ Quisque auctor varius fermentum. Praesent mollis justo sit amet est consectetur, in
+ volutpat tellus mollis. Aenean at bibendum eros, at finibus nibh. Phasellus nec mi sem.
+ Mauris pellentesque dui sit amet lobortis aliquam. Ut nec massa at urna aliquam gravida vel
+ in magna. Donec consectetur sapien magna, a auctor sapien placerat eu.
+
+ Pellentesque aliquet ante sed lacus gravida rutrum. Maecenas euismod varius felis, nec
+ tempus metus tempus et. Nam convallis augue a massa scelerisque, vel pharetra dolor
+ scelerisque. Fusce porttitor mi a magna rutrum condimentum. Aliquam fermentum at turpis at
+ auctor. Nulla ut suscipit dui. Donec rutrum viverra aliquam. Donec elementum nisl sapien, ac
+ blandit risus porta facilisis. Proin tellus dolor, ornare vel magna sit amet, maximus
+ volutpat felis. Aenean euismod aliquet purus, at finibus nunc elementum eu. Ut faucibus
+ ullamcorper consectetur. Aenean egestas arcu id mauris elementum, at sollicitudin est
+ congue. Sed a odio mattis, sollicitudin erat ut, tristique dolor. Aliquam luctus risus quis
+ tellus semper, a vestibulum nulla viverra.
+
+ Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
+ himenaeos. Vestibulum sit amet nisi felis. Praesent condimentum consequat lacus pulvinar
+ imperdiet. Praesent vel condimentum quam. Maecenas eu aliquet odio. Vestibulum sed nulla
+ mattis lacus porta bibendum a ac eros. Nunc porttitor sagittis laoreet. Duis porta eros at
+ congue tristique. Pellentesque quis fringilla neque, a hendrerit tellus. Pellentesque ac
+ nibh ac tellus pulvinar porttitor et in est. Integer blandit lorem libero, eu pulvinar
+ tellus posuere eget. Vivamus pretium nulla ligula, ut dapibus massa fringilla in.
+ Suspendisse consectetur sem non elit porta, id pellentesque erat dapibus. Quisque ex mi,
+ tempus et hendrerit nec, gravida quis odio. Ut at mi in leo scelerisque venenatis.
+
+ Ut sed tellus in risus tincidunt tempor ut at arcu. Maecenas ut convallis justo. In
+ rutrum urna eu massa rhoncus, eget condimentum augue vehicula. Nullam eget placerat erat.
+ Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+ Aenean at volutpat orci, a lobortis dolor. Sed consequat facilisis interdum. Fusce libero
+ neque, fringilla in congue a, vehicula rutrum ipsum. Nam ornare placerat vestibulum. Proin
+ nec orci velit. Pellentesque scelerisque gravida diam, ut tristique libero tempus eu. Nam
+ semper lacus nec nulla volutpat imperdiet non eget tortor. Sed et pellentesque ligula.
+
+ Aenean a dolor dolor. Curabitur ut placerat lacus, sit amet aliquet orci. Aliquam erat
+ volutpat. Cras mollis sit amet lectus ornare pretium. Vestibulum fringilla orci vel est
+ iaculis, at mattis quam condimentum. Vivamus semper elit consectetur lectus gravida, in
+ sollicitudin mi fringilla. Donec eget lorem in orci blandit aliquam. Pellentesque libero
+ tellus, dignissim id augue et, vulputate viverra nisl. Cum sociis natoque penatibus et
+ magnis dis parturient montes, nascetur ridiculus mus. Donec ac vulputate metus, eu suscipit
+ sem. Donec placerat, nulla at sodales hendrerit, orci tortor vestibulum purus, non pharetra
+ nulla purus posuere arcu.
+
+ Quisque feugiat elit sem, ac interdum diam pharetra nec. Curabitur sem libero, vulputate
+ eu libero vitae, volutpat facilisis ligula. Aenean maximus erat laoreet, interdum ante in,
+ ultrices nisi. Nullam nec efficitur sapien. Integer feugiat et tortor ac bibendum. Donec a
+ scelerisque tortor. Cras quis viverra diam, vitae viverra ipsum. Aliquam ultrices neque sem,
+ congue sodales elit tempus sit amet. Pellentesque habitant morbi tristique senectus et netus
+ et malesuada fames ac turpis egestas. Sed dignissim ipsum eget diam rhoncus, ut finibus
+ nulla pretium. Morbi suscipit nibh vel nisl posuere molestie. Maecenas posuere turpis et
+ rutrum consectetur. Morbi venenatis arcu non gravida vulputate. Vivamus auctor tellus
+ ullamcorper ligula vestibulum cursus. Nunc gravida sit amet nisl quis facilisis.
+
+ Praesent ut justo vestibulum, accumsan mi et, feugiat purus. Nullam pulvinar iaculis
+ pharetra. Aliquam pulvinar risus sit amet elit suscipit tincidunt. In hac habitasse platea
+ dictumst. Etiam eget velit ac magna lacinia efficitur. Vestibulum ante ipsum primis in
+ faucibus orci luctus et ultrices posuere cubilia Curae; Cras volutpat tempus sollicitudin.
+ Ut et ante elit.
+
+ Sed ac tortor justo. Fusce sed metus libero. Duis sagittis tortor ac ante sollicitudin,
+ nec efficitur nibh euismod. Donec porttitor cursus quam, in aliquam lorem feugiat ut.
+ Aliquam tempor lacus eu feugiat feugiat. Nunc pulvinar, libero at auctor commodo, metus diam
+ commodo lorem, in feugiat elit ex non ligula. Quisque at vestibulum sapien, nec facilisis
+ neque. Aenean luctus, arcu ut rhoncus luctus, est massa rhoncus mauris, nec luctus urna sem
+ quis massa. Nam elit felis, congue et ligula eget, ultricies tincidunt erat. Vivamus
+ eleifend no dui ac dictum. In nulla justo, pulvinar ut tristique sed, congue et orci.
+
+ Quisque imperdiet mi lectus, ac scelerisque augue posuere ut. Duis non pulvinar ipsum,
+ finibus risus. Donec ullamcorper nisl at sodales lobortis. Mauris neque leo, vestibulum sit
+ amet placerat vel, aliquet vel sapien. Morbi massa tellus, scelerisque quis nisl in, feugiat
+ posuere augue. Aenean congue sem ut ipsum vulputate rhoncus vitae at eros. Maecenas in velit
+ orci pellentesque lobortis ac at felis. Vestibulum odio quam, lacinia dapibus ornare eu,
+ vulputate a eros. Curabitur eleifend ornare tellus, non sollicitudin justo viverra in. Sed
+ sodales neque et lacus semper, in pharetra est consequat. Nunc vehicula volutpat lectus, sit
+ amet scelerisque nisi. Aenean sollicitudin, sem at ultricies efficitur, eros metus
+ nisl, et fringilla felis lacus non orci. Praesent eros libero, finibus in purus id,
+ tempor ipsum. Donec suscipit libero velit. Aliquam quis diam pharetra, cursus ipsum in,
+ gravida metus. Maecenas ultrices ligula a ullamcorper scelerisque.
+
+ Donec tincidunt felis turpis, id venenatis neque convallis in. Proin euismod ligula nec
+ urna vulputate, sed elementum mauris ultrices. Ut efficitur sem vel mi vestibulum placerat.
+ Sed fermentum lacus nec metus dictum, a commodo quam fermentum. Sed vel vulputate magna.
+ Integer convallis nisi sit amet mi lobortis pellentesque. In egestas porttitor elit eu
+ scelerisque. Suspendisse eleifend vel enim quis tincidunt. Sed placerat risus et pretium
+ porttitor. Nam justo mi, cursus eu pellentesque vel, bibendum ut nisl. Nulla condimentum
+ lorem, non sagittis lorem volutpat vitae. Mauris nec libero lorem. Vestibulum lacus ex,
+ vulputate non massa vitae, pellentesque vestibulum dolor.
+
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+ Suspendisse vitae erat nisl. Vestibulum elit ante, semper et semper sit amet, fringilla
+ sapien. Morbi ac nisi sit amet turpis tincidunt mattis ac eget nisl. Nunc a venenatis quam,
+ facilisis maximus odio. Aliquam erat volutpat. Maecenas leo enim, ornare a magna quis,
+ venenatis ornare nulla. Aliquam venenatis nibh et elit tincidunt, ut egestas lorem finibus.
+ Integer iaculis dolor sed enim blandit vestibulum. Nullam vel libero ultricies, sagittis
+ tortor non, molestie eros.</string>
</resources>
diff --git a/tests/tests/assist/service/AndroidManifest.xml b/tests/tests/assist/service/AndroidManifest.xml
index 5a22d31..354d771 100644
--- a/tests/tests/assist/service/AndroidManifest.xml
+++ b/tests/tests/assist/service/AndroidManifest.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.assist.service">
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
<application>
<uses-library android:name="android.test.runner" />
<service android:name=".MainInteractionService"
@@ -43,6 +45,10 @@
<action android:name="android.intent.action.START_TEST_ASSIST_STRUCTURE" />
<action android:name="android.intent.action.START_TEST_LIFECYCLE" />
<action android:name="android.intent.action.START_TEST_FLAG_SECURE" />
+ <action android:name="android.intent.action.START_TEST_SCREENSHOT" />
+ <action android:name="android.intent.action.START_TEST_EXTRA_ASSIST" />
+ <action android:name="android.intent.action.START_TEST_TEXTVIEW" />
+ <action android:name="android.intent.action.START_TEST_LARGE_VIEW_HIERARCHY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
diff --git a/tests/tests/assist/service/res/layout/assist_layer.xml b/tests/tests/assist/service/res/layout/assist_layer.xml
index 49f35c9..3677208 100644
--- a/tests/tests/assist/service/res/layout/assist_layer.xml
+++ b/tests/tests/assist/service/res/layout/assist_layer.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/assist_layer"
- android:layout_width="match_parent"
- android:background="@color/assist_layer_background"
- android:layout_height="match_parent">
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/assist_layer"
+ android:layout_width="match_parent"
+ android:background="@color/assist_layer_background"
+ android:layout_height="match_parent">
<TextView
android:layout_centerInParent="true"
android:text="@string/test_assistant_text"
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
index b7d67f1..ddf43bd 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
@@ -26,11 +26,17 @@
public class DelayedAssistantActivity extends Activity {
static final String TAG = "DelayedAssistantActivity";
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent();
intent.setComponent(new ComponentName(this, MainInteractionService.class));
intent.putExtra(Utils.EXTRA_REGISTER_RECEIVER, true);
+ intent.putExtra(Utils.TESTCASE_TYPE, getIntent().getStringExtra(Utils.TESTCASE_TYPE));
+ intent.putExtra(Utils.DISPLAY_WIDTH_KEY,
+ getIntent().getIntExtra(Utils.DISPLAY_WIDTH_KEY, 0));
+ intent.putExtra(Utils.DISPLAY_HEIGHT_KEY,
+ getIntent().getIntExtra(Utils.DISPLAY_HEIGHT_KEY, 0));
finish();
ComponentName serviceName = startService(intent);
Log.i(TAG, "Started service: " + serviceName);
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
index fc19e1c..916d676 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -30,11 +30,17 @@
import android.service.voice.VoiceInteractionSession;
import android.util.Log;
+import java.lang.Exception;
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
public class MainInteractionService extends VoiceInteractionService {
static final String TAG = "MainInteractionService";
private Intent mIntent;
private boolean mReady = false;
- private BroadcastReceiver mBroadcastReceiver;
+ private BroadcastReceiver mBroadcastReceiver, mResumeReceiver;
+ private CountDownLatch mResumeLatch;
@Override
public void onReady() {
@@ -57,17 +63,27 @@
} else {
if (isActiveService(this, new ComponentName(this, getClass()))) {
if (mIntent.getBooleanExtra(Utils.EXTRA_REGISTER_RECEIVER, false)) {
- Log.i(TAG, "Registering receiver to start session later");
+ mResumeLatch = new CountDownLatch(1);
if (mBroadcastReceiver == null) {
mBroadcastReceiver = new MainInteractionServiceBroadcastReceiver();
- registerReceiver(mBroadcastReceiver,
- new IntentFilter(Utils.BROADCAST_INTENT_START_ASSIST));
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.BROADCAST_INTENT_START_ASSIST);
+ registerReceiver(mBroadcastReceiver, filter);
+ Log.i(TAG, "Registered receiver to start session later");
+
+ IntentFilter resumeFilter = new IntentFilter(Utils.APP_3P_HASRESUMED);
+ mResumeReceiver = new MainServiceAppResumeReceiver();
+ registerReceiver(mResumeReceiver, resumeFilter);
+ Log.i(TAG, "Registered receiver for resuming activity");
}
sendBroadcast(new Intent(Utils.ASSIST_RECEIVER_REGISTERED));
} else {
Log.i(TAG, "Yay! about to start session");
- showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
- VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
+ Bundle bundle = new Bundle();
+ bundle.putString(Utils.TESTCASE_TYPE,
+ mIntent.getStringExtra(Utils.TESTCASE_TYPE));
+ showSession(bundle, VoiceInteractionSession.SHOW_WITH_ASSIST |
+ VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
}
} else {
Log.wtf(TAG, "**** Not starting MainInteractionService because" +
@@ -81,7 +97,49 @@
public void onReceive(Context context, Intent intent) {
Log.i(MainInteractionService.TAG, "Recieved broadcast to start session now.");
if (intent.getAction().equals(Utils.BROADCAST_INTENT_START_ASSIST)) {
- showSession(new Bundle(), SHOW_WITH_ASSIST | SHOW_WITH_SCREENSHOT);
+ String testCaseName = intent.getStringExtra(Utils.TESTCASE_TYPE);
+ Log.i(MainInteractionService.TAG, "trying to start 3p activity: " + testCaseName);
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ if (testCaseName.equals(Utils.SCREENSHOT)) {
+ try {
+ // extra info to pass along to 3p activity.
+
+ Intent intent3p = new Intent();
+ Log.i(TAG, "starting the 3p app again");
+ intent3p.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent3p.setAction("android.intent.action.TEST_APP_" + testCaseName);
+ intent3p.setComponent(Utils.getTestAppComponent(testCaseName));
+ intent3p.putExtras(extras);
+ startActivity(intent3p);
+ if (!MainInteractionService.this.mResumeLatch
+ .await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ Log.i(TAG, "waited for 3p activity to resume");
+ }
+ } catch (Exception e) {
+ Log.i(TAG, "failed so reload 3p app: " + e.toString());
+ }
+ }
+ extras.putString(Utils.TESTCASE_TYPE, mIntent.getStringExtra(Utils.TESTCASE_TYPE));
+ MainInteractionService.this.showSession(
+ extras, SHOW_WITH_ASSIST | SHOW_WITH_SCREENSHOT);
+ }
+ }
+ }
+
+ private class MainServiceAppResumeReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Utils.APP_3P_HASRESUMED)) {
+ Log.i(MainInteractionService.TAG,
+ "3p activity has resumed in this new receiver");
+ if (MainInteractionService.this.mResumeLatch != null) {
+ MainInteractionService.this.mResumeLatch.countDown();
+ } else {
+ Log.i(TAG, "mResumeLatch was null");
+ }
}
}
}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
index 38d03f8..7bca9be 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -24,15 +24,24 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
+import android.graphics.Color;
+
+import android.graphics.Point;
import android.os.Bundle;
import android.service.voice.VoiceInteractionSession;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.Display;
+import android.view.ViewTreeObserver;
import java.io.ByteArrayOutputStream;
+import java.util.Date;
import android.assist.common.Utils;
+import android.view.WindowManager;
public class MainInteractionSession extends VoiceInteractionSession {
static final String TAG = "MainInteractionSession";
@@ -43,7 +52,13 @@
private boolean hasReceivedAssistData = false;
private boolean hasReceivedScreenshot = false;
+ private int mCurColor;
+ private int mDisplayHeight;
+ private int mDisplayWidth;
+ private Bitmap mScreenshot;
private BroadcastReceiver mReceiver;
+ private String mTestName;
+ private View mContentView;
MainInteractionSession(Context context) {
super(context);
@@ -78,13 +93,30 @@
@Override
public void onShow(Bundle args, int showFlags) {
- // set some content view.
- // TODO: check that the view takes up the whole screen.
- // check that interactor mode is for assist
if ((showFlags & SHOW_WITH_ASSIST) == 0) {
return;
}
+ mTestName = args.getString(Utils.TESTCASE_TYPE, "");
+ mCurColor = args.getInt(Utils.SCREENSHOT_COLOR_KEY);
+ mDisplayHeight = args.getInt(Utils.DISPLAY_HEIGHT_KEY);
+ mDisplayWidth = args.getInt(Utils.DISPLAY_WIDTH_KEY);
super.onShow(args, showFlags);
+ mContentView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mContentView.getViewTreeObserver().removeOnPreDrawListener(this);
+ Display d = mContentView.getDisplay();
+ Point displayPoint = new Point();
+ d.getRealSize(displayPoint);
+ Intent intent = new Intent(Utils.BROADCAST_CONTENT_VIEW_HEIGHT);
+ intent.putExtra(Utils.EXTRA_CONTENT_VIEW_HEIGHT, mContentView.getHeight());
+ intent.putExtra(Utils.EXTRA_CONTENT_VIEW_WIDTH, mContentView.getWidth());
+ intent.putExtra(Utils.EXTRA_DISPLAY_POINT, displayPoint);
+ mContext.sendBroadcast(intent);
+ return true;
+ }
+ });
}
@Override
@@ -107,17 +139,52 @@
public void onHandleScreenshot(/*@Nullable*/ Bitmap screenshot) {
Log.i(TAG, String.format("onHandleScreenshot - Screenshot: %s", screenshot));
super.onHandleScreenshot(screenshot);
- ByteArrayOutputStream bs = new ByteArrayOutputStream();
+
if (screenshot != null) {
- screenshot.compress(Bitmap.CompressFormat.PNG, 50, bs);
- mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, bs.toByteArray());
+ mAssistData.putBoolean(Utils.ASSIST_SCREENSHOT_KEY, true);
+
+ if (mTestName.equals(Utils.SCREENSHOT)) {
+ boolean screenshotMatches = compareScreenshot(screenshot, mCurColor);
+ Log.i(TAG, "this is a screenshot test. Matches? " + screenshotMatches);
+ mAssistData.putBoolean(
+ Utils.COMPARE_SCREENSHOT_KEY, screenshotMatches);
+ }
} else {
- mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, null);
+ mAssistData.putBoolean(Utils.ASSIST_SCREENSHOT_KEY, false);
}
hasReceivedScreenshot = true;
maybeBroadcastResults();
}
+ private boolean compareScreenshot(Bitmap screenshot, int color) {
+ Point size = new Point(mDisplayWidth, mDisplayHeight);
+
+ if (screenshot.getWidth() != size.x || screenshot.getHeight() != size.y) {
+ Log.i(TAG, "width or height didn't match: " + size + " vs " + screenshot.getWidth()
+ + "," + screenshot.getHeight());
+ return false;
+ }
+ int[] pixels = new int[size.x * size.y];
+ screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
+
+ int expectedColor = 0;
+ int wrongColor = 0;
+ for (int pixel : pixels) {
+ if (pixel == color) {
+ expectedColor += 1;
+ } else {
+ wrongColor += 1;
+ }
+ }
+
+ double colorRatio = (double) expectedColor / (expectedColor + wrongColor);
+ Log.i(TAG, "the ratio is " + colorRatio);
+ if (colorRatio < 0.6) {
+ return false;
+ }
+ return true;
+ }
+
private void maybeBroadcastResults() {
if (!hasReceivedAssistData) {
Log.i(TAG, "waiting for assist data before broadcasting results");
@@ -141,13 +208,7 @@
if (f == null) {
Log.wtf(TAG, "layout inflater was null");
}
- return f.inflate(R.layout.assist_layer,null);
- }
-
- class DoneReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "Done_broadcast " + intent.getAction());
- }
+ mContentView = f.inflate(R.layout.assist_layer,null);
+ return mContentView;
}
}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index 8ff235b..4c1b1f3 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -34,10 +34,12 @@
*/
public class AssistStructureTest extends AssistTestBase {
+ private static final String TAG = "AssistStructureTest";
private static final String TEST_CASE_TYPE = Utils.ASSIST_STRUCTURE;
private BroadcastReceiver mReceiver;
private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
public AssistStructureTest() {
super();
@@ -65,7 +67,7 @@
}
mReceiver = new AssistStructureTestBroadcastReceiver();
IntentFilter filter = new IntentFilter();
- filter.addAction(Utils.ASSIST_STRUCTURE_HASRESUMED);
+ filter.addAction(Utils.APP_3P_HASRESUMED);
filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
mContext.registerReceiver(mReceiver, filter);
}
@@ -80,7 +82,7 @@
public void testAssistStructure() throws Exception {
mTestActivity.start3pApp(TEST_CASE_TYPE);
mTestActivity.startTest(TEST_CASE_TYPE);
- waitForAssistantToBeReady();
+ waitForAssistantToBeReady(mReadyLatch);
waitForOnResume();
startSession();
waitForContext();
@@ -94,11 +96,15 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(Utils.ASSIST_STRUCTURE_HASRESUMED)) {
- mHasResumedLatch.countDown();
+ if (action.equals(Utils.APP_3P_HASRESUMED)) {
+ if (mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ }
} else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
- mAssistantReadyLatch.countDown();
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 25460e5..46fb8d9 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -33,31 +33,41 @@
import android.cts.util.SystemUtil;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Bundle;
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.webkit.WebView;
+import android.widget.EditText;
import android.widget.TextView;
+import java.lang.Math;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AssistTestBase extends ActivityInstrumentationTestCase2<TestStartActivity> {
- static final String TAG = "AssistTestBase";
+ private static final String TAG = "AssistTestBase";
protected TestStartActivity mTestActivity;
protected AssistContent mAssistContent;
protected AssistStructure mAssistStructure;
- protected Bitmap mScreenshot;
+ protected boolean mScreenshot;
+ protected Bitmap mAppScreenshot;
protected BroadcastReceiver mReceiver;
protected Bundle mAssistBundle;
protected Context mContext;
- protected CountDownLatch mLatch, mAssistantReadyLatch;
-
+ protected CountDownLatch mLatch, mScreenshotLatch, mHasResumedLatch;
+ protected boolean mScreenshotMatches;
+ private Point mDisplaySize;
private String mTestName;
private View mView;
@@ -68,29 +78,49 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mAssistantReadyLatch = new CountDownLatch(1);
mContext = getInstrumentation().getTargetContext();
SystemUtil.runShellCommand(getInstrumentation(),
"settings put secure assist_structure_enabled 1");
SystemUtil.runShellCommand(getInstrumentation(),
"settings put secure assist_screenshot_enabled 1");
logContextAndScreenshotSetting();
+
+ // reset old values
+ mScreenshotMatches = false;
+ mScreenshot = false;
+ mAssistStructure = null;
+ mAssistContent = null;
+ mAssistBundle = null;
+
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new TestResultsReceiver();
+ mContext.registerReceiver(mReceiver,
+ new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
}
@Override
protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
mTestActivity.finish();
- super.tearDown();
mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION));
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ super.tearDown();
}
+ /**
+ * Starts the shim service activity
+ */
protected void startTestActivity(String testName) {
Intent intent = new Intent();
mTestName = testName;
intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + testName);
intent.setComponent(new ComponentName(getInstrumentation().getContext(),
TestStartActivity.class));
+ intent.putExtra(Utils.TESTCASE_TYPE, testName);
setActivityIntent(intent);
mTestActivity = getActivity();
}
@@ -98,9 +128,9 @@
/**
* Called when waiting for Assistant's Broadcast Receiver to be setup
*/
- public void waitForAssistantToBeReady() throws Exception {
+ public void waitForAssistantToBeReady(CountDownLatch latch) throws Exception {
Log.i(TAG, "waiting for assistant to be ready before continuing");
- if (!mAssistantReadyLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ if (!latch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
fail("Assistant was not ready before timeout of: " + Utils.TIMEOUT_MS + "msec");
}
}
@@ -109,11 +139,33 @@
* Send broadcast to MainInteractionService to start a session
*/
protected void startSession() {
- mContext.sendBroadcast(new Intent(Utils.BROADCAST_INTENT_START_ASSIST));
+ startSession(mTestName, new Bundle());
+ }
+
+ protected void startSession(String testName, Bundle extras) {
+ Intent intent = new Intent(Utils.BROADCAST_INTENT_START_ASSIST);
+ Log.i(TAG, "passed in class test name is: " + testName);
+ intent.putExtra(Utils.TESTCASE_TYPE, testName);
+ addDimensionsToIntent(intent);
+ intent.putExtras(extras);
+ mContext.sendBroadcast(intent);
}
/**
- * Called after startTestActivity
+ * Calculate display dimensions (including navbar) to pass along in the given intent.
+ */
+ private void addDimensionsToIntent(Intent intent) {
+ if (mDisplaySize == null) {
+ Display display = mTestActivity.getWindowManager().getDefaultDisplay();
+ mDisplaySize = new Point();
+ display.getRealSize(mDisplaySize);
+ }
+ intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x);
+ intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y);
+ }
+
+ /**
+ * Called after startTestActivity. Includes check for receiving context.
*/
protected boolean waitForBroadcast() throws Exception {
mTestActivity.start3pApp(mTestName);
@@ -123,15 +175,16 @@
protected boolean waitForContext() throws Exception {
mLatch = new CountDownLatch(1);
+
if (mReceiver != null) {
mContext.unregisterReceiver(mReceiver);
}
mReceiver = new TestResultsReceiver();
mContext.registerReceiver(mReceiver,
- new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
+ new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
- if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
+ if (!mLatch.await(Utils.getAssistDataTimeout(mTestName), TimeUnit.MILLISECONDS)) {
+ fail("Fail to receive broadcast in " + Utils.getAssistDataTimeout(mTestName) + "msec");
}
Log.i(TAG, "Received broadcast with all information.");
return true;
@@ -150,26 +203,43 @@
if ((mAssistContent == null) != isContentNull) {
fail(String.format("Should %s have been null - AssistContent: %s",
- isContentNull? "":"not", mAssistContent));
+ isContentNull ? "" : "not", mAssistContent));
}
if ((mAssistStructure == null) != isStructureNull) {
fail(String.format("Should %s have been null - AssistStructure: %s",
- isStructureNull ? "" : "not", mAssistStructure));
+ isStructureNull ? "" : "not", mAssistStructure));
}
if ((mAssistBundle == null) != isBundleNull) {
fail(String.format("Should %s have been null - AssistBundle: %s",
- isBundleNull? "":"not", mAssistBundle));
+ isBundleNull ? "" : "not", mAssistBundle));
}
- if ((mScreenshot == null) != isScreenshotNull) {
+ if (mScreenshot == isScreenshotNull) {
fail(String.format("Should %s have been null - Screenshot: %s",
- isScreenshotNull? "":"not", mScreenshot));
+ isScreenshotNull ? "":"not", mScreenshot));
}
}
/**
+ * Sends a broadcast with the specified scroll positions to the test app.
+ */
+ protected void scrollTestApp(int scrollX, int scrollY, boolean scrollTextView,
+ boolean scrollScrollView) {
+ mTestActivity.scrollText(scrollX, scrollY, scrollTextView, scrollScrollView);
+ Intent intent = null;
+ if (scrollTextView) {
+ intent = new Intent(Utils.SCROLL_TEXTVIEW_ACTION);
+ } else if (scrollScrollView) {
+ intent = new Intent(Utils.SCROLL_SCROLLVIEW_ACTION);
+ }
+ intent.putExtra(Utils.SCROLL_X_POSITION, scrollX);
+ intent.putExtra(Utils.SCROLL_Y_POSITION, scrollY);
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
* Verifies the view hierarchy of the backgroundApp matches the assist structure.
*
* @param backgroundApp ComponentName of app the assistant is invoked upon
@@ -178,7 +248,7 @@
protected void verifyAssistStructure(ComponentName backgroundApp, boolean isSecureWindow) {
// Check component name matches
assertEquals(backgroundApp.flattenToString(),
- mAssistStructure.getActivityComponent().flattenToString());
+ mAssistStructure.getActivityComponent().flattenToString());
Log.i(TAG, "Traversing down structure for: " + backgroundApp.flattenToString());
mView = mTestActivity.findViewById(android.R.id.content).getRootView();
@@ -187,7 +257,7 @@
protected void logContextAndScreenshotSetting() {
Log.i(TAG, "Context is: " + Settings.Secure.getString(
- mContext.getContentResolver(), "assist_structure_enabled"));
+ mContext.getContentResolver(), "assist_structure_enabled"));
Log.i(TAG, "Screenshot is: " + Settings.Secure.getString(
mContext.getContentResolver(), "assist_screenshot_enabled"));
}
@@ -240,9 +310,10 @@
+ ((ViewGroup) parentView).getChildAt(childInt).getClass().getName());
}
}
+ String parentViewId = null;
if (parentView.getId() > 0) {
- Log.i(TAG, "View ID: "
- + mTestActivity.getResources().getResourceEntryName(parentView.getId()));
+ parentViewId = mTestActivity.getResources().getResourceEntryName(parentView.getId());
+ Log.i(TAG, "View ID: " + parentViewId);
}
Log.i(TAG, "parentNode is of type: " + parentNode.getClassName());
@@ -251,7 +322,9 @@
"nodechild" + nodeInt + " is of type: "
+ parentNode.getChildAt(nodeInt).getClassName());
}
- Log.i(TAG, "Node ID: " + parentNode.getIdEntry());
+ Log.i(TAG, "Node ID: " + parentNode.getIdEntry());
+
+ assertEquals("IDs do not match", parentViewId, parentNode.getIdEntry());
int numViewChildren = 0;
int numNodeChildren = 0;
@@ -260,31 +333,57 @@
}
numNodeChildren = parentNode.getChildCount();
- if (isSecureWindow) {
+ if (isSecureWindow) {
+ assertTrue("ViewNode property isAssistBlocked is false", parentNode.isAssistBlocked());
assertEquals("Secure window should only traverse root node.", 0, numNodeChildren);
isSecureWindow = false;
- return;
+ } else if (parentNode.getClassName().equals("android.webkit.WebView")) {
+ // WebView will also appear to have no children while the node does, traverse node
+ assertTrue("AssistStructure returned a WebView where the view wasn't one",
+ parentView instanceof WebView);
+
+ boolean textInWebView = false;
+
+ for (int i = numNodeChildren - 1; i >= 0; i--) {
+ textInWebView |= traverseWebViewForText(parentNode.getChildAt(i));
+ }
+ assertTrue("Did not find expected strings inside WebView", textInWebView);
} else {
assertEquals("Number of children did not match.", numViewChildren, numNodeChildren);
- }
- verifyViewProperties(parentView, parentNode);
+ verifyViewProperties(parentView, parentNode);
- if (parentView instanceof ViewGroup) {
- parentGroup = (ViewGroup) parentView;
+ if (parentView instanceof ViewGroup) {
+ parentGroup = (ViewGroup) parentView;
- // TODO: set a max recursion level
- for (int i = numNodeChildren - 1; i >= 0; i--) {
- View childView = parentGroup.getChildAt(i);
- ViewNode childNode = parentNode.getChildAt(i);
+ // TODO: set a max recursion level
+ for (int i = numNodeChildren - 1; i >= 0; i--) {
+ View childView = parentGroup.getChildAt(i);
+ ViewNode childNode = parentNode.getChildAt(i);
- // if isSecureWindow, should not have reached this point.
- assertFalse(isSecureWindow);
- traverseViewAndStructure(childView, childNode, isSecureWindow);
+ // if isSecureWindow, should not have reached this point.
+ assertFalse(isSecureWindow);
+ traverseViewAndStructure(childView, childNode, isSecureWindow);
+ }
}
}
}
+ /**
+ * Return true if the expected strings are found in the WebView, else fail.
+ */
+ private boolean traverseWebViewForText(ViewNode parentNode) {
+ boolean textFound = false;
+ if (parentNode.getText() != null
+ && parentNode.getText().toString().equals(Utils.WEBVIEW_HTML_GREETING)) {
+ return true;
+ }
+ for (int i = parentNode.getChildCount() - 1; i >= 0; i--) {
+ textFound |= traverseWebViewForText(parentNode.getChildAt(i));
+ }
+ return textFound;
+ }
+
/**
* Compare view properties of the view hierarchy with that reported in the assist structure.
*/
@@ -304,21 +403,48 @@
assertNull("View Node should not have an ID.", parentNode.getIdEntry());
}
- assertEquals("Scroll X does not match.",
- parentView.getScrollX(), parentNode.getScrollX());
+ Log.i(TAG, "parent text: " + parentNode.getText());
+ if (parentView instanceof TextView) {
+ Log.i(TAG, "view text: " + ((TextView) parentView).getText());
+ }
- assertEquals("Scroll Y does not match.",
- parentView.getScrollY(), parentNode.getScrollY());
- assertEquals("Heights do not match.", parentView.getHeight(),
- parentNode.getHeight());
-
+ assertEquals("Scroll X does not match.", parentView.getScrollX(), parentNode.getScrollX());
+ assertEquals("Scroll Y does not match.", parentView.getScrollY(), parentNode.getScrollY());
+ assertEquals("Heights do not match.", parentView.getHeight(), parentNode.getHeight());
assertEquals("Widths do not match.", parentView.getWidth(), parentNode.getWidth());
- // TODO: handle unicode/i18n
if (parentView instanceof TextView) {
- assertEquals("Text in TextView does not match.",
- ((TextView) parentView).getText().toString(), parentNode.getText());
+ if (parentView instanceof EditText) {
+ assertEquals("Text selection start does not match",
+ ((EditText)parentView).getSelectionStart(), parentNode.getTextSelectionStart());
+ assertEquals("Text selection end does not match",
+ ((EditText)parentView).getSelectionEnd(), parentNode.getTextSelectionEnd());
+ }
+ TextView textView = (TextView) parentView;
+ assertEquals(textView.getTextSize(), parentNode.getTextSize());
+ String viewString = textView.getText().toString();
+ String nodeString = parentNode.getText().toString();
+
+ if (parentNode.getScrollX() == 0 && parentNode.getScrollY() == 0) {
+ Log.i(TAG, "Verifying text within TextView at the beginning");
+ Log.i(TAG, "view string: " + viewString);
+ Log.i(TAG, "node string: " + nodeString);
+ assertTrue("String length is unexpected: original string - " + viewString.length() +
+ ", string in AssistData - " + nodeString.length(),
+ viewString.length() >= nodeString.length());
+ assertTrue("Expected a longer string to be shown. expected: "
+ + Math.min(viewString.length(), 30) + " was: " + nodeString
+ .length(),
+ nodeString.length() >= Math.min(viewString.length(), 30));
+ for (int x = 0; x < parentNode.getText().length(); x++) {
+ assertEquals("Char not equal at index: " + x,
+ ((TextView) parentView).getText().toString().charAt(x),
+ parentNode.getText().charAt(x));
+ }
+ } else if (parentNode.getScrollX() == parentView.getWidth()) {
+
+ }
} else {
assertNull(parentNode.getText());
}
@@ -336,17 +462,20 @@
AssistTestBase.this.mAssistContent = assistData.getParcelable(
Utils.ASSIST_CONTENT_KEY);
- byte[] bitmapArray = assistData.getByteArray(Utils.ASSIST_SCREENSHOT_KEY);
- if (bitmapArray != null) {
- AssistTestBase.this.mScreenshot = BitmapFactory.decodeByteArray(
- bitmapArray, 0, bitmapArray.length);
- } else {
- AssistTestBase.this.mScreenshot = null;
- }
+ AssistTestBase.this.mScreenshot =
+ assistData.getBoolean(Utils.ASSIST_SCREENSHOT_KEY, false);
+
+ AssistTestBase.this.mScreenshotMatches = assistData.getBoolean(
+ Utils.COMPARE_SCREENSHOT_KEY, false);
if (mLatch != null) {
+ Log.i(AssistTestBase.TAG, "counting down latch. received assist data.");
mLatch.countDown();
}
+ } else if (intent.getAction().equals(Utils.APP_3P_HASRESUMED)) {
+ if (mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ }
}
}
}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
new file mode 100644
index 0000000..557134b
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.cts.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test verifying the Content View of the Assistant */
+public class AssistantContentViewTest extends AssistTestBase {
+ private static final String TAG = "ContentViewTest";
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mContentViewLatch, mReadyLatch;
+ private Intent mIntent;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContentViewLatch = new CountDownLatch(1);
+ mReadyLatch = new CountDownLatch(1);
+ setUpAndRegisterReceiver();
+ startTestActivity(Utils.VERIFY_CONTENT_VIEW);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new AssistantContentViewReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.BROADCAST_CONTENT_VIEW_HEIGHT);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ mContext.registerReceiver(mReceiver, filter);
+
+ }
+
+ private void waitForContentView() throws Exception {
+ Log.i(TAG, "waiting for the Assistant's Content View before continuing");
+ if (!mContentViewLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("failed to receive content view in " + Utils.TIMEOUT_MS + "msec");
+ }
+ }
+
+ public void testAssistantContentViewDimens() throws Exception {
+ mTestActivity.startTest(Utils.VERIFY_CONTENT_VIEW);
+ waitForAssistantToBeReady(mReadyLatch);
+ startSession();
+ waitForContentView();
+ int height = mIntent.getIntExtra(Utils.EXTRA_CONTENT_VIEW_HEIGHT, 0);
+ int width = mIntent.getIntExtra(Utils.EXTRA_CONTENT_VIEW_WIDTH, 0);
+ Point displayPoint = (Point) mIntent.getParcelableExtra(Utils.EXTRA_DISPLAY_POINT);
+ assertEquals(displayPoint.y, height);
+ assertEquals(displayPoint.x, width);
+ }
+
+ private class AssistantContentViewReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.BROADCAST_CONTENT_VIEW_HEIGHT)) {
+ mIntent = intent;
+ if (mContentViewLatch != null) {
+ mContentViewLatch.countDown();
+ }
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index dc28879..5c8aa19 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
import java.lang.Override;
import java.util.concurrent.CountDownLatch;
@@ -63,6 +64,7 @@
public void testContextAndScreenshotOff() throws Exception {
// Both settings off
+ Log.i(TAG, "DisableContext: Screenshot OFF, Context OFF");
SystemUtil.runShellCommand(getInstrumentation(),
"settings put secure assist_structure_enabled 0");
SystemUtil.runShellCommand(getInstrumentation(),
@@ -74,6 +76,7 @@
verifyAssistDataNullness(true, true, true, true);
// Screenshot off, context on
+ Log.i(TAG, "DisableContext: Screenshot OFF, Context ON");
SystemUtil.runShellCommand(getInstrumentation(),
"settings put secure assist_structure_enabled 1");
SystemUtil.runShellCommand(getInstrumentation(),
@@ -85,6 +88,7 @@
verifyAssistDataNullness(false, false, false, true);
// Context off, screenshot on
+ Log.i(TAG, "DisableContext: Screenshot ON, Context OFF");
SystemUtil.runShellCommand(getInstrumentation(),
"settings put secure assist_structure_enabled 0");
SystemUtil.runShellCommand(getInstrumentation(),
@@ -95,4 +99,4 @@
verifyAssistDataNullness(true, true, true, true);
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
new file mode 100644
index 0000000..28b2af2
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.assist.cts;
+
+import android.assist.common.Utils;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ExtraAssistDataTest extends AssistTestBase {
+ private static final String TAG = "ExtraAssistDataTest";
+ private static final String TEST_CASE_TYPE = Utils.EXTRA_ASSIST;
+
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+ public ExtraAssistDataTest() {
+ super();
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ setUpAndRegisterReceiver();
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new ExtraAssistDataReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.APP_3P_HASRESUMED);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ public void testAssistContentAndAssistData() throws Exception {
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ waitForAssistantToBeReady(mReadyLatch);
+ mTestActivity.start3pApp(TEST_CASE_TYPE);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistDataNullness(false, false, false, false);
+
+ Log.i(TAG, "assist bundle is: " + Utils.toBundleString(mAssistBundle));
+
+ // tests that the assist content's structured data is the expected
+ assertEquals("AssistContent structured data did not match data in onProvideAssistContent",
+ Utils.getStructuredJSON(), mAssistContent.getStructuredData());
+ // tests the assist data. EXTRA_ASSIST_CONTEXT is what's expected.
+ Bundle extraExpectedBundle = Utils.getExtraAssistBundle();
+ Bundle extraAssistBundle = mAssistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+ for (String key : extraExpectedBundle.keySet()) {
+ assertTrue("Assist bundle does not contain expected extra context key: " + key,
+ extraAssistBundle.containsKey(key));
+ assertEquals("Extra assist context bundle values do not match for key: " + key,
+ extraExpectedBundle.get(key), extraAssistBundle.get(key));
+ }
+ }
+
+ private void waitForOnResume() throws Exception {
+ Log.i(TAG, "waiting for onResume() before continuing");
+ if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+ }
+
+ private class ExtraAssistDataReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.APP_3P_HASRESUMED)) {
+ if (mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ }
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
index 2e9932e..35f95a4 100644
--- a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -37,7 +37,7 @@
private BroadcastReceiver mReceiver;
private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
-
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
public FlagSecureTest() {
super();
}
@@ -78,7 +78,7 @@
public void testSecureActivity() throws Exception {
mTestActivity.startTest(TEST_CASE_TYPE);
- waitForAssistantToBeReady();
+ waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(TEST_CASE_TYPE);
waitForOnResume();
startSession();
@@ -93,9 +93,13 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Utils.FLAG_SECURE_HASRESUMED)) {
- mHasResumedLatch.countDown();
+ if (mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ }
} else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
- mAssistantReadyLatch.countDown();
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
}
}
}
diff --git a/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
new file mode 100644
index 0000000..f6b90b9
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.cts.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test that triggering the Assistant causes the underlying Activity to lose focus **/
+
+public class FocusChangeTest extends AssistTestBase {
+ private static final String TAG = "FocusChangeTest";
+ private static final String TEST_CASE_TYPE = Utils.FOCUS_CHANGE;
+
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mHasGainedFocusLatch = new CountDownLatch(1);
+ private CountDownLatch mHasLostFocusLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ setUpAndRegisterReceiver();
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new FocusChangeTestReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.GAINED_FOCUS);
+ filter.addAction(Utils.LOST_FOCUS);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ private void waitToGainFocus() throws Exception {
+ Log.i(TAG, "Waiting for the underlying activity to gain focus before continuing.");
+ if (!mHasGainedFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to gain focus in " + Utils.TIMEOUT_MS + "msec.");
+ }
+ }
+
+ private void waitToLoseFocus() throws Exception {
+ Log.i(TAG, "Waiting for the underlying activity to lose focus.");
+ if (!mHasLostFocusLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity maintained focus despite the Assistant Firing"
+ + Utils.TIMEOUT_MS + "msec.");
+ }
+ }
+
+ public void testLayerCausesUnderlyingActivityToLoseFocus() throws Exception {
+ mTestActivity.startTest(Utils.FOCUS_CHANGE);
+ waitForAssistantToBeReady(mReadyLatch);
+ mTestActivity.start3pApp(Utils.FOCUS_CHANGE);
+ waitToGainFocus();
+ startSession();
+ waitToLoseFocus();
+ }
+
+ private class FocusChangeTestReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.GAINED_FOCUS) && mHasGainedFocusLatch != null) {
+ mHasGainedFocusLatch.countDown();
+ } else if (action.equals(Utils.LOST_FOCUS) && mHasLostFocusLatch != null) {
+ mHasLostFocusLatch.countDown();
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
new file mode 100644
index 0000000..bc2ab80
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test that the AssistStructure returned is properly formatted.
+ */
+
+public class LargeViewHierarchyTest extends AssistTestBase {
+ private static final String TAG = "LargeViewHierarchyTest";
+ private static final String TEST_CASE_TYPE = Utils.LARGE_VIEW_HIERARCHY;
+
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+ public LargeViewHierarchyTest() {
+ super();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setUpAndRegisterReceiver();
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new LargeViewTestBroadcastReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.APP_3P_HASRESUMED);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ private void waitForOnResume() throws Exception {
+ Log.i(TAG, "waiting for onResume() before continuing");
+ if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+ }
+
+ public void testTextView() throws Exception {
+ mTestActivity.start3pApp(TEST_CASE_TYPE);
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ waitForAssistantToBeReady(mReadyLatch);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistDataNullness(false, false, false, false);
+
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+ false /*FLAG_SECURE set*/);
+ }
+
+ private class LargeViewTestBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) && mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
index 7451017..c886b74 100644
--- a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -46,15 +46,18 @@
private static final String action_onStop = Utils.LIFECYCLE_ONSTOP;
private static final String action_onDestroy = Utils.LIFECYCLE_ONDESTROY;
+ private static final String TEST_CASE_TYPE = Utils.LIFECYCLE;
+
private BroadcastReceiver mLifecycleTestBroadcastReceiver;
private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
private CountDownLatch mActivityLifecycleLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
@Override
public void setUp() throws Exception {
super.setUp();
setUpAndRegisterReceiver();
- startTestActivity(Utils.LIFECYCLE);
+ startTestActivity(TEST_CASE_TYPE);
}
@Override
@@ -96,7 +99,7 @@
public void testLayerDoesNotTriggerLifecycleMethods() throws Exception {
mTestActivity.startTest(Utils.LIFECYCLE);
- waitForAssistantToBeReady();
+ waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(Utils.LIFECYCLE);
waitForOnResume();
startSession();
@@ -108,16 +111,18 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(action_hasResumed)) {
+ if (action.equals(action_hasResumed) && mHasResumedLatch != null) {
mHasResumedLatch.countDown();
- } else if (action.equals(action_onPause)) {
+ } else if (action.equals(action_onPause) && mActivityLifecycleLatch != null) {
mActivityLifecycleLatch.countDown();
- } else if (action.equals(action_onStop)) {
+ } else if (action.equals(action_onStop) && mActivityLifecycleLatch != null) {
mActivityLifecycleLatch.countDown();
- } else if (action.equals(action_onDestroy)) {
+ } else if (action.equals(action_onDestroy) && mActivityLifecycleLatch != null) {
mActivityLifecycleLatch.countDown();
} else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
- mAssistantReadyLatch.countDown();
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
}
}
}
diff --git a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
new file mode 100644
index 0000000..45082ae
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.DatabaseUtils;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+
+import junit.framework.Test;
+
+import java.lang.Exception;
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ScreenshotTest extends AssistTestBase {
+ static final String TAG = "ScreenshotTest";
+
+ private static final String TEST_CASE_TYPE = Utils.SCREENSHOT;
+
+ private BroadcastReceiver mScreenshotActivityReceiver;
+ private CountDownLatch mHasResumedLatch, mReadyLatch;
+
+ public ScreenshotTest() {
+ super();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mReadyLatch = new CountDownLatch(1);
+ // set up receiver
+ mScreenshotActivityReceiver = new ScreenshotTestReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ filter.addAction(Utils.APP_3P_HASRESUMED);
+ mContext.registerReceiver(mScreenshotActivityReceiver, filter);
+
+ // start test start activity
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mScreenshotActivityReceiver != null) {
+ mContext.unregisterReceiver(mScreenshotActivityReceiver);
+ }
+ super.tearDown();
+ }
+
+ public void testRedScreenshot() throws Exception {
+ Log.i(TAG, "Starting screenshot test");
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ Log.i(TAG, "start waitForAssistantToBeReady()");
+ waitForAssistantToBeReady(mReadyLatch);
+
+ waitForActivityResumeAndAssist(Color.RED);
+ verifyAssistDataNullness(false, false, false, false);
+ assertTrue(mScreenshotMatches);
+ }
+
+ public void testGreenScreenshot() throws Exception {
+ Log.i(TAG, "Starting screenshot test");
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ Log.i(TAG, "start waitForAssistantToBeReady()");
+ waitForAssistantToBeReady(mReadyLatch);
+
+ waitForActivityResumeAndAssist(Color.GREEN);
+ verifyAssistDataNullness(false, false, false, false);
+ assertTrue(mScreenshotMatches);
+ }
+
+ public void testBlueScreenshot() throws Exception {
+ Log.i(TAG, "Starting screenshot test");
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ Log.i(TAG, "start waitForAssistantToBeReady()");
+ waitForAssistantToBeReady(mReadyLatch);
+
+ waitForActivityResumeAndAssist(Color.BLUE);
+ verifyAssistDataNullness(false, false, false, false);
+ assertTrue(mScreenshotMatches);
+ }
+
+ private void waitForActivityResumeAndAssist(int color) throws Exception {
+ mHasResumedLatch = new CountDownLatch(1);
+ Bundle extras = new Bundle();
+ extras.putInt(Utils.SCREENSHOT_COLOR_KEY, color);
+ startSession(TEST_CASE_TYPE, extras);
+ Log.i(TAG, "waiting for onResume() before continuing.");
+ if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+ waitForContext();
+ }
+
+ private class ScreenshotTestReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.i(ScreenshotTest.TAG, "Got some broadcast: " + action);
+ if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+ Log.i(ScreenshotTest.TAG, "Received assist receiver is registered.");
+ if (mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ } else if (action.equals(Utils.APP_3P_HASRESUMED)) {
+ if (mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/TestStartActivity.java b/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
index 16c924f..e54e774 100644
--- a/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
+++ b/tests/tests/assist/src/android/assist/cts/TestStartActivity.java
@@ -23,21 +23,62 @@
import android.app.assist.AssistStructure.ViewNode;
import android.content.Intent;
import android.content.ComponentName;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ScrollView;
import android.widget.TextView;
+import java.lang.Override;
+
public class TestStartActivity extends Activity {
static final String TAG = "TestStartActivity";
+ private ScrollView mScrollView;
+ private TextView mTextView;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, " in onCreate");
- setContentView(R.layout.test_app);
+ // Set the respective view we want compared with the test activity
+ String testName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+ switch (testName) {
+ case Utils.ASSIST_STRUCTURE:
+ setContentView(R.layout.test_app);
+ setTitle(R.string.testAppTitle);
+ return;
+ case Utils.TEXTVIEW:
+ setContentView(R.layout.text_view);
+ mTextView = (TextView) findViewById(R.id.text_view);
+ mScrollView = (ScrollView) findViewById(R.id.scroll_view);
+ setTitle(R.string.textViewActivityTitle);
+ return;
+ case Utils.LARGE_VIEW_HIERARCHY:
+ setContentView(R.layout.multiple_text_views);
+ setTitle(R.string.testAppTitle);
+ return;
+ case Utils.WEBVIEW:
+ if (getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WEBVIEW)) {
+ setContentView(R.layout.webview);
+ setTitle(R.string.webViewActivityTitle);
+ WebView webview = (WebView) findViewById(R.id.webview);
+ webview.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ sendBroadcast(new Intent(Utils.TEST_ACTIVITY_LOADED));
+ }
+ });
+ webview.loadData(Utils.WEBVIEW_HTML, "text/html", "UTF-8");
+ }
+ return;
+ }
}
@Override
@@ -58,17 +99,28 @@
public void start3pApp(String testCaseName) {
Intent intent = new Intent();
+ intent.putExtra(Utils.TESTCASE_TYPE, testCaseName);
intent.setAction("android.intent.action.TEST_APP_" + testCaseName);
intent.setComponent(Utils.getTestAppComponent(testCaseName));
startActivity(intent);
}
- @Override protected void onPause() {
+ public void start3pAppWithColor(String testCaseName, int color) {
+ Intent intent = new Intent();
+ intent.setAction("android.intent.action.TEST_APP_" + testCaseName);
+ intent.putExtra(Utils.SCREENSHOT_COLOR_KEY, color);
+ intent.setComponent(Utils.getTestAppComponent(testCaseName));
+ startActivity(intent);
+ }
+
+ @Override
+ protected void onPause() {
Log.i(TAG, " in onPause");
super.onPause();
}
- @Override protected void onStart() {
+ @Override
+ protected void onStart() {
super.onStart();
Log.i(TAG, " in onStart");
}
@@ -78,7 +130,8 @@
Log.i(TAG, " in onRestart");
}
- @Override protected void onStop() {
+ @Override
+ protected void onStop() {
Log.i(TAG, " in onStop");
super.onStop();
}
@@ -88,4 +141,25 @@
Log.i(TAG, " in onDestroy");
super.onDestroy();
}
+
+ public void scrollText(int scrollX, int scrollY, boolean scrollTextView,
+ boolean scrollScrollView) {
+ if (scrollTextView) {
+ if (scrollX < 0 || scrollY < 0) {
+ scrollX = mTextView.getWidth();
+ scrollY = mTextView.getLayout().getLineTop(mTextView.getLineCount()) - mTextView.getHeight();
+ }
+ Log.i(TAG, "Scrolling text view to " + scrollX + ", " + scrollY);
+ mTextView.scrollTo(scrollX, scrollY);
+ } else if (scrollScrollView) {
+ if (scrollX < 0 || scrollY < 0) {
+ Log.i(TAG, "Scrolling scroll view to bottom right");
+ mScrollView.fullScroll(View.FOCUS_DOWN);
+ mScrollView.fullScroll(View.FOCUS_RIGHT);
+ } else {
+ Log.i(TAG, "Scrolling scroll view to " + scrollX + ", " + scrollY);
+ mScrollView.scrollTo(scrollX, scrollY);
+ }
+ }
+ }
}
diff --git a/tests/tests/assist/src/android/assist/cts/TextViewTest.java b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
new file mode 100644
index 0000000..e4390bc
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test that the AssistStructure returned is properly formatted.
+ */
+
+public class TextViewTest extends AssistTestBase {
+ private static final String TAG = "TextViewTest";
+ private static final String TEST_CASE_TYPE = Utils.TEXTVIEW;
+
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+ public TextViewTest() {
+ super();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setUpAndRegisterReceiver();
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new TextViewTestBroadcastReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.APP_3P_HASRESUMED);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ private void waitForOnResume() throws Exception {
+ Log.i(TAG, "waiting for onResume() before continuing");
+ if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+ }
+
+ public void testTextView() throws Exception {
+ mTestActivity.start3pApp(TEST_CASE_TYPE);
+ scrollTestApp(0, 0, true, false);
+
+ // Verify that the text view contains the right text
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ waitForAssistantToBeReady(mReadyLatch);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistDataNullness(false, false, false, false);
+
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+ false /*FLAG_SECURE set*/);
+
+ // Verify that the scroll position of the text view is accurate after scrolling.
+ scrollTestApp(10, 50, true /* scrollTextView */, false /* scrollScrollView */);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+ scrollTestApp(-1, -1, true, false);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+ scrollTestApp(0, 0, true, true);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+
+ scrollTestApp(10, 50, false, true);
+ waitForOnResume();
+ startSession();
+ waitForContext();
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false);
+ }
+
+ private class TextViewTestBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) && mReadyLatch != null) {
+ mReadyLatch.countDown();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/WebViewTest.java b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
new file mode 100644
index 0000000..e367e22
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.cts;
+
+import android.assist.common.Utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test that the AssistStructure returned is properly formatted.
+ */
+
+public class WebViewTest extends AssistTestBase {
+ private static final String TAG = "WebViewTest";
+ private static final String TEST_CASE_TYPE = Utils.WEBVIEW;
+
+ private boolean mWebViewSupported;
+ private BroadcastReceiver mReceiver;
+ private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+ private CountDownLatch mTestWebViewLatch = new CountDownLatch(1);
+ private CountDownLatch mReadyLatch = new CountDownLatch(1);
+
+ public WebViewTest() {
+ super();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setUpAndRegisterReceiver();
+ startTestActivity(TEST_CASE_TYPE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+
+ private void setUpAndRegisterReceiver() {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mReceiver = new WebViewTestBroadcastReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.APP_3P_HASRESUMED);
+ filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+ filter.addAction(Utils.TEST_ACTIVITY_LOADED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ private void waitForOnResume() throws Exception {
+ Log.i(TAG, "waiting for onResume() before continuing");
+ if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+ }
+ }
+
+ private void waitForTestActivity() throws Exception {
+ Log.i(TAG, "waiting for webview in test activity to load");
+ if (!mTestWebViewLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ // wait for webView to load completely.
+ }
+ }
+
+ public void testWebView() throws Exception {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+ return;
+ }
+ mTestActivity.start3pApp(TEST_CASE_TYPE);
+ mTestActivity.startTest(TEST_CASE_TYPE);
+ waitForAssistantToBeReady(mReadyLatch);
+ waitForOnResume();
+ waitForTestActivity();
+ startSession();
+ waitForContext();
+ verifyAssistDataNullness(false, false, false, false);
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+ false /*FLAG_SECURE set*/);
+ }
+
+ private class WebViewTestBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Utils.APP_3P_HASRESUMED) && mHasResumedLatch != null) {
+ mHasResumedLatch.countDown();
+ } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED) && mReadyLatch != null) {
+ mReadyLatch.countDown();
+ } else if (action.equals(Utils.TEST_ACTIVITY_LOADED) && mTestWebViewLatch != null) {
+ mTestWebViewLatch.countDown();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
index f14cf22..fa08f55 100644
--- a/tests/tests/assist/testapp/AndroidManifest.xml
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -18,41 +18,79 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.assist.testapp">
+ <uses-permission android:name="android.permission.INTERNET" />
+
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="TestApp"
- android:label="Assist Structure Test App"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name=".TestApp"
+ android:label="Assist Structure Test Activity">
<intent-filter>
<action android:name="android.intent.action.TEST_APP_ASSIST_STRUCTURE" />
+ <action android:name="android.intent.action.TEST_APP_LARGE_VIEWHIERARCHY" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE" />
</intent-filter>
</activity>
- <activity android:name="DisableContextActivity"
- android:label="Disable Context Test Activity"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name=".DisableContextActivity"
+ android:label="Disable Context Test Activity">
<intent-filter>
<action android:name="android.intent.action.TEST_APP_DISABLE_CONTEXT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
- <activity android:name="SecureActivity"
- android:label="Secure Test Activity"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name=".SecureActivity"
+ android:label="Secure Test Activity">
<intent-filter>
<action android:name="android.intent.action.TEST_APP_FLAG_SECURE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE" />
</intent-filter>
</activity>
- <activity android:name="LifecycleActivity"
- android:label="Life Cycle Check Activity"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name=".LifecycleActivity"
+ android:label="Life Cycle Check Activity">
<intent-filter>
<action android:name="android.intent.action.TEST_APP_LIFECYCLE" />
<category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".ScreenshotActivity"
+ android:label="Screenshot Test Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.TEST_APP_SCREENSHOT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".ExtraAssistDataActivity"
+ android:label="Extra Assist Test Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.TEST_APP_EXTRA_ASSIST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".TextViewActivity"
+ android:label="TextView Test Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.TEST_APP_TEXTVIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".WebViewActivity"
+ android:label="WebView Test Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.TEST_APP_WEBVIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".FocusChangeActivity"
+ android:label="Focus Change Test Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.TEST_APP_FOCUS_CHANGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
</intent-filter>
</activity>
</application>
diff --git a/tests/tests/assist/testapp/res/layout/multiple_text_views.xml b/tests/tests/assist/testapp/res/layout/multiple_text_views.xml
new file mode 100644
index 0000000..455d5e3
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/multiple_text_views.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+
+ <ScrollView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+ </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/screenshot_activity.xml b/tests/tests/assist/testapp/res/layout/screenshot_activity.xml
new file mode 100644
index 0000000..05051dc
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/screenshot_activity.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/screenshot_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/text_view.xml b/tests/tests/assist/testapp/res/layout/text_view.xml
new file mode 100644
index 0000000..0f0f427
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/text_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:focusable="false"
+ android:focusableInTouchMode="false"
+ android:scrollbars="vertical"
+ android:clickable="true"
+ android:text="@string/text_too_large_to_fit" />
+
+ <ScrollView
+ android:id="@+id/scroll_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:text="@string/text_too_large_to_fit" />
+ </ScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/layout/webview.xml b/tests/tests/assist/testapp/res/layout/webview.xml
new file mode 100644
index 0000000..bdb8082
--- /dev/null
+++ b/tests/tests/assist/testapp/res/layout/webview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <WebView
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </WebView>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/res/values/strings.xml b/tests/tests/assist/testapp/res/values/strings.xml
index ae4f16e..670024b 100644
--- a/tests/tests/assist/testapp/res/values/strings.xml
+++ b/tests/tests/assist/testapp/res/values/strings.xml
@@ -14,5 +14,271 @@
limitations under the License.
-->
<resources>
+
+ <string name="app_name">Memegen</string>
+ <string name="hello_world">Hello world!</string>
+ <string name="action_settings">Settings</string>
<string name="welcome">Hello there!</string>
+ <string name="text_too_large_to_fit">❤ ☀ ☆ ☂ ☻ ♞ ☯ ☭ ☢ € →Hello هتاف للترحيب שלום
+ përshëndetje Добры дзень 您好 হ্যালো здравей მიესალმები Χαίρετε હેલો नमस्ते Nnọọ こんにちは ಹಲೋ
+ Сәлеметсіз бе ជំរាបសួរ 안녕하세요 ສະບາຍດີ ഹലോ हॅलो Сайн байна уу नमस्ते سلامהעלא ہیلو
+ မင်္ဂလာပါ ਸਤ ਸ੍ਰੀ ਅਕਾਲ Здравствуйте здраво ආයුබෝවන් ஹலோ హలో สวัสดี Pẹlẹ o
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ convallis nunc et vestibulum. Sed et consequat quam, blandit varius tortor. Curabitur
+ accumsan nulla lectus, placerat condimentum odio elementum vel. Nulla erat ex, accumsan ut
+ enim sagittis, scelerisque efficitur ante. Nullam quis orci nec magna maximus malesuada ac
+ id sem. Nam sagittis erat risus, a accumsan neque congue sit amet. Nullam risus velit,
+ faucibus eget scelerisque et, maximus eget arcu. Sed porta sed libero ac imperdiet.
+
+ Nulla sem lectus, ullamcorper id dui vel, rutrum interdum augue. Proin aliquam nisi vitae
+ hendrerit tempor. Mauris porttitor velit et egestas feugiat. Vivamus eu dapibus libero,
+ quis fringilla urna. Suspendisse non turpis dui. Vivamus facilisis diam vitae est auctor
+ luctus. Etiam quis lectus viverra, interdum turpis eu, aliquam sem. Nulla vulputate lacinia
+ nisi a dictum. Cras faucibus vitae tortor at ullamcorper. Quisque sit amet sapien maximus,
+ ornare nisi non, imperdiet magna. Vestibulum tempor metus ac mi ultrices dapibus.
+
+ Suspendisse potenti. Mauris pellentesque lacinia tristique. Pellentesque vel dui quis sem
+ lacinia imperdiet feugiat vitae sem. Proin a arcu magna. Sed quis augue eu mi accumsan
+ pellentesque pretium in leo. Duis euismod purus mauris, ac tempor erat auctor non. Quisque
+ bibendum est pulvinar ex dapibus, ac tincidunt nibh tempus. Mauris sodales sem id purus
+ commodo iaculis. Pellentesque a quam dapibus, vehicula lectus at, tincidunt arcu. In
+ placerat porttitor urna quis consequat. Nullam feugiat nisl sed urna hendrerit, sed
+ elementum massa iaculis. Fusce sit amet turpis hendrerit, varius lorem sed, luctus mi.
+ Phasellus sit amet ex orci. Duis scelerisque nisl quis efficitur maximus. Curabitur vitae
+ accumsan nunc, eget varius nisi.
+
+ Fusce efficitur malesuada luctus. Aliquam dapibus tortor sit amet purus semper, sit amet
+ pretium lorem feugiat. Maecenas gravida sed arcu et placerat. Nulla facilisi. Cras placerat
+ rutrum mi, in rutrum mauris maximus at. Mauris eu suscipit ante. Nullam pharetra egestas
+ diam a viverra. Donec sem turpis, tempor malesuada est vel, blandit accumsan magna. In
+ iaculis velit in efficitur hendrerit. Nulla facilisi. Curabitur eget ligula lorem. Sed sit
+ amet dolor ut ligula malesuada condimentum. Phasellus molestie augue eget libero commodo,
+ vel blandit ex blandit.
+
+ Morbi cursus tortor ante, et tempus nisi tempus et. Suspendisse quis gravida diam. Aliquam
+ efficitur dolor sit amet sollicitudin varius. Etiam libero purus, ornare nec nulla vel,
+ ullamcorper blandit nisl. Sed vel consequat diam, id placerat sem. Donec quis elementum
+ urna. In posuere bibendum nunc, in condimentum justo blandit ac. Quisque enim lorem,
+ gravida at purus at, sollicitudin imperdiet erat. Ut consectetur rutrum ante, et pretium
+ odio iaculis a. Nullam a nibh vulputate, volutpat lectus eu, pellentesque felis. Nam
+ vehicula suscipit diam nec convallis. Quisque congue maximus sem, sit amet hendrerit leo
+ tempor et.
+
+ Nam eu consequat dui. Sed semper dignissim mattis. Integer tortor eros, tempor in lectus a,
+ lobortis aliquam dolor. Phasellus at sagittis magna. Nulla eleifend orci ac urna auctor,
+ sit amet luctus urna vulputate. Nulla venenatis venenatis erat ac finibus. Etiam
+ ullamcorper elementum suscipit. Morbi nec velit non mauris porta finibus. Nullam in
+ sagittis odio. Praesent eget nisl ut mauris vestibulum feugiat. Sed vulputate at elit et
+ cursus. Praesent viverra erat blandit nunc egestas, vel feugiat ex condimentum. Class
+ aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+
+ Nulla fermentum mattis urna, non gravida eros vestibulum et. Fusce porttitor augue turpis,
+ sit amet aliquam augue sodales non. Nunc neque odio, sagittis sed gravida euismod, commodo
+ at libero. Donec porttitor pulvinar neque vitae lobortis. Aliquam accumsan velit nec sapien
+ placerat egestas. Aliquam at tincidunt massa, et dignissim justo. Donec sapien ante, rutrum
+ et tristique a, commodo a massa.
+
+ Nunc placerat lobortis magna, et molestie lacus semper porta. Lorem ipsum dolor sit amet,
+ consectetur adipiscing elit. Phasellus ac ligula dui. Duis ultrices viverra eros fermentum
+ finibus. Integer ultrices, felis in accumsan volutpat, mi ligula hendrerit nunc, nec
+ accumsan mauris tellus sit amet metus. Ut pharetra enim et sapien sollicitudin, nec
+ ultricies urna pharetra. Morbi non tortor nec dui feugiat rutrum. Aliquam malesuada sodales
+ risus, sed congue nunc accumsan vitae. Etiam nunc magna, tempus non suscipit eu, feugiat ut
+ nibh. Maecenas et libero ut nisl pellentesque tempor nec vel quam. Etiam sem ligula,
+ ullamcorper non dolor a, viverra placerat nulla. Nullam dictum commodo dui, sed ultrices
+ enim sagittis eget. Morbi non consectetur lectus. In gravida, augue vitae pulvinar
+ molestie, ligula orci vulputate ex, at bibendum urna felis nec nibh. Sed nisl nunc, iaculis
+ at augue venenatis, fringilla accumsan velit. Curabitur nec augue porttitor, rutrum nisi
+ vitae, elementum orci.
+
+ Vestibulum eu tortor iaculis, dignissim velit quis, rhoncus dolor. Donec et tincidunt
+ nulla. Duis faucibus auctor erat ac ultricies. In a fermentum mi. Fusce vitae mi id sem
+ interdum tincidunt. Nulla hendrerit orci turpis, in maximus elit mollis eget. Aliquam erat
+ volutpat. Phasellus mattis est nibh, ut scelerisque ligula egestas eu. Ut molestie orci a
+ malesuada tempor. Sed tempus arcu id orci gravida faucibus. Vivamus ac lacinia neque, at
+ vehicula magna.
+
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+ Nullam aliquam, justo scelerisque egestas sodales, purus odio posuere arcu, ac ultrices
+ nunc felis non massa. Aliquam vulputate ipsum sed aliquet auctor. In pulvinar, eros sit
+ amet ultricies tristique, lacus ipsum scelerisque eros, nec vestibulum est lectus quis
+ lorem. Pellentesque ac augue ut eros mattis viverra vitae ut lacus. Phasellus imperdiet
+ efficitur elit eget tincidunt. Donec sodales metus at dolor pulvinar, at gravida nibh
+ facilisis. Sed nec tellus luctus, cursus lacus sed, euismod orci. Maecenas sit amet leo
+ orci. Nulla non leo non mi eleifend consequat sit amet vitae dui. Sed gravida gravida
+ justo, tincidunt ultrices justo semper vitae. Fusce at nisi nisl. Morbi molestie quis justo
+ a convallis. Curabitur massa lacus, feugiat quis mauris ac, malesuada viverra est.
+
+ Phasellus bibendum faucibus velit, ac scelerisque velit tincidunt eu. Curabitur quis
+ suscipit erat, ac feugiat odio. Nullam et sapien et nibh maximus posuere. Vivamus faucibus
+ justo eget dictum sollicitudin. Etiam at leo eget elit facilisis lobortis. Maecenas
+ bibendum tortor non erat pretium dignissim. Fusce id imperdiet augue. Suspendisse dignissim
+ magna vel odio viverra varius. Maecenas suscipit ante et lorem sodales vehicula. Quisque
+ vel magna id sem suscipit iaculis. Etiam in elementum risus.
+
+ Suspendisse odio nisi, pharetra et purus sit amet, placerat lobortis diam. Phasellus enim
+ nunc, posuere sed porta in, ornare eu ipsum. Phasellus imperdiet porta neque, vitae dapibus
+ tellus feugiat eget. Nulla sodales leo ac efficitur luctus. Vivamus eget ipsum quis ante
+ pulvinar blandit. Vestibulum a justo convallis justo elementum viverra ut sit amet nisl.
+ Suspendisse eget augue fermentum, sagittis risus a, rhoncus elit. Vestibulum in maximus
+ tortor, non vestibulum libero. Nunc accumsan neque a nisl dapibus, id laoreet neque congue.
+ Pellentesque sapien odio, fringilla non nulla nec, varius placerat diam. Aliquam
+ consectetur neque eu ipsum posuere, nec dignissim sem faucibus. Donec sit amet tempor
+ sapien. Nam at libero vel lorem dapibus ultrices a vel augue. Nunc facilisis justo ante,
+ mollis tristique velit aliquet quis. Mauris consectetur odio at urna bibendum aliquam.
+
+ Nullam lectus orci, hendrerit ut ultrices in, dapibus pellentesque nibh. Aliquam arcu
+ metus, lobortis vel dignissim id, tempus ut ante. Integer vitae ante augue. In hac habitasse
+ platea dictumst. Vestibulum in tellus ante. Cras nisi tellus, congue ac velit quis, rhoncus
+ ornare ligula. Sed facilisis gravida pellentesque. Praesent id ultrices orci, ac ultricies
+ arcu. Donec at ante quis augue faucibus congue. Donec mattis quam dui, ut vestibulum orci
+ tempor mattis. Phasellus in quam id tortor varius ullamcorper ac ac ante. Proin cursus
+ accumsan sem, vel finibus lectus eleifend ut. Donec efficitur feugiat diam id ultricies. In
+ quis euismod nisi. Vestibulum eget viverra sapien. Donec scelerisque nec elit vel viverra.
+
+ Sed mi urna, rutrum quis augue vel, aliquet placerat diam. Proin faucibus in odio et
+ consequat. Proin ut ex in mauris eleifend efficitur. Praesent ullamcorper sollicitudin urna,
+ sed mollis elit hendrerit non. Duis leo lorem, efficitur eu auctor sit amet, scelerisque
+ scelerisque magna. Mauris eget massa auctor, viverra arcu a, elementum nibh. Sed
+ pellentesque, nulla sed condimentum posuere, tortor metus congue sem, nec placerat neque
+ magna vitae purus.
+
+ Etiam at risus vitae sapien aliquam condimentum. Vestibulum id libero placerat purus
+ vehicula consectetur. Pellentesque sapien sapien, posuere at pulvinar at, ultrices sed est.
+ Maecenas nec condimentum ante. Aenean volutpat, ex condimentum hendrerit hendrerit, quam
+ nisl pharetra nibh, vitae bibendum nisl odio vel lacus. Morbi mi tellus, bibendum id mauris
+ eu, facilisis volutpat turpis. Maecenas rutrum convallis felis. Quisque eget feugiat felis.
+ Duis pellentesque iaculis massa ut facilisis. Donec nec commodo magna. Integer aliquet orci
+ a odio eleifend elementum. Quisque molestie, urna ut molestie eleifend, odio neque maximus
+ enim, eget viverra metus lectus eget quam. Fusce nec urna ac neque bibendum aliquam vel quis
+ dui. Fusce ac quam consequat, feugiat leo vitae, auctor felis.
+
+ Sed ac metus mauris. Sed sed velit ut tortor aliquam vestibulum at eu arcu. Etiam eu
+ posuere lacus. Maecenas id lacus quis sem mollis sodales. Quisque justo sapien, vulputate ac
+ mi ut, congue vestibulum orci. Donec euismod erat rutrum, laoreet urna sed, accumsan purus.
+ Donec eu quam a sapien condimentum accumsan. Sed at tellus lorem. Curabitur bibendum, arcu
+ sit amet finibus sodales, mi sem finibus sem, eget scelerisque tellus neque vel urna.
+ Suspendisse eu augue nec erat suscipit luctus sed non metus.
+
+ Suspendisse porttitor ex ipsum. Pellentesque tristique eros sed pharetra porttitor.
+ Quisque ut elit vehicula, aliquet est nec, faucibus tellus. Donec ex augue, congue eu
+ dignissim maximus, vestibulum at purus. Nulla quam enim, laoreet sit amet molestie vel,
+ dapibus nec tortor. Sed interdum massa ac orci gravida, vel viverra lacus lacinia. Donec
+ nisl lacus, fermentum at faucibus ac, consequat ut nibh. Praesent laoreet est augue, vitae
+ maximus dui efficitur sit amet. Cras ipsum tellus, tincidunt at volutpat non, tincidunt ut
+ elit. Morbi commodo sagittis gravida. Pellentesque sed ante massa. Phasellus a turpis non
+ turpis cursus consequat sed nec tortor. Proin et augue elit.
+
+ Duis finibus sem commodo rutrum pulvinar. In sollicitudin ante magna, vel facilisis
+ tellus fringilla vel. Nam purus ex, tincidunt eget varius at, euismod nec elit. Curabitur
+ consequat nulla vel nisi iaculis, ut mattis odio congue. Nulla et mollis tortor, a maximus
+ justo. Donec semper eros sed nunc rhoncus condimentum. Donec nibh purus, interdum non lectus
+ id, porta convallis eros.
+
+ Sed hendrerit, dui non sagittis sollicitudin, enim ex imperdiet sapien, et maximus lorem
+ dolor a enim. Nulla risus nisl, vestibulum at ornare posuere, congue in felis. Duis sagittis
+ id diam a varius. Donec viverra eu orci sodales commodo. Cras metus tortor, sodales vitae
+ auctor non, scelerisque a ante. Quisque sodales nisi libero, ut lobortis enim suscipit ut.
+ Cras mi ipsum, maximus non bibendum sit amet, pharetra quis ipsum. Vestibulum venenatis, odi
+ at hendrerit pretium, tellus diam auctor justo, non posuere quam mauris id nisl. Nam dolor
+ nibh, molestie et lectus et, scelerisque porta elit. Vestibulum viverra condimentum auctor.
+ In eros tortor, convallis sed quam eu, ultrices malesuada purus. Integer lorem quam,
+ ultricies at est consectetur, sagittis porttitor eros. Proin non risus vitae lacus
+ consectetur malesuada non pulvinar justo. Aliquam mollis nisi nunc, sit amet vulputate metus
+ sollicitudin vel.
+
+ Quisque auctor varius fermentum. Praesent mollis justo sit amet est consectetur, in
+ volutpat tellus mollis. Aenean at bibendum eros, at finibus nibh. Phasellus nec mi sem.
+ Mauris pellentesque dui sit amet lobortis aliquam. Ut nec massa at urna aliquam gravida vel
+ in magna. Donec consectetur sapien magna, a auctor sapien placerat eu.
+
+ Pellentesque aliquet ante sed lacus gravida rutrum. Maecenas euismod varius felis, nec
+ tempus metus tempus et. Nam convallis augue a massa scelerisque, vel pharetra dolor
+ scelerisque. Fusce porttitor mi a magna rutrum condimentum. Aliquam fermentum at turpis at
+ auctor. Nulla ut suscipit dui. Donec rutrum viverra aliquam. Donec elementum nisl sapien, ac
+ blandit risus porta facilisis. Proin tellus dolor, ornare vel magna sit amet, maximus
+ volutpat felis. Aenean euismod aliquet purus, at finibus nunc elementum eu. Ut faucibus
+ ullamcorper consectetur. Aenean egestas arcu id mauris elementum, at sollicitudin est
+ congue. Sed a odio mattis, sollicitudin erat ut, tristique dolor. Aliquam luctus risus quis
+ tellus semper, a vestibulum nulla viverra.
+
+ Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
+ himenaeos. Vestibulum sit amet nisi felis. Praesent condimentum consequat lacus pulvinar
+ imperdiet. Praesent vel condimentum quam. Maecenas eu aliquet odio. Vestibulum sed nulla
+ mattis lacus porta bibendum a ac eros. Nunc porttitor sagittis laoreet. Duis porta eros at
+ congue tristique. Pellentesque quis fringilla neque, a hendrerit tellus. Pellentesque ac
+ nibh ac tellus pulvinar porttitor et in est. Integer blandit lorem libero, eu pulvinar
+ tellus posuere eget. Vivamus pretium nulla ligula, ut dapibus massa fringilla in.
+ Suspendisse consectetur sem non elit porta, id pellentesque erat dapibus. Quisque ex mi,
+ tempus et hendrerit nec, gravida quis odio. Ut at mi in leo scelerisque venenatis.
+
+ Ut sed tellus in risus tincidunt tempor ut at arcu. Maecenas ut convallis justo. In
+ rutrum urna eu massa rhoncus, eget condimentum augue vehicula. Nullam eget placerat erat.
+ Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
+ Aenean at volutpat orci, a lobortis dolor. Sed consequat facilisis interdum. Fusce libero
+ neque, fringilla in congue a, vehicula rutrum ipsum. Nam ornare placerat vestibulum. Proin
+ nec orci velit. Pellentesque scelerisque gravida diam, ut tristique libero tempus eu. Nam
+ semper lacus nec nulla volutpat imperdiet non eget tortor. Sed et pellentesque ligula.
+
+ Aenean a dolor dolor. Curabitur ut placerat lacus, sit amet aliquet orci. Aliquam erat
+ volutpat. Cras mollis sit amet lectus ornare pretium. Vestibulum fringilla orci vel est
+ iaculis, at mattis quam condimentum. Vivamus semper elit consectetur lectus gravida, in
+ sollicitudin mi fringilla. Donec eget lorem in orci blandit aliquam. Pellentesque libero
+ tellus, dignissim id augue et, vulputate viverra nisl. Cum sociis natoque penatibus et
+ magnis dis parturient montes, nascetur ridiculus mus. Donec ac vulputate metus, eu suscipit
+ sem. Donec placerat, nulla at sodales hendrerit, orci tortor vestibulum purus, non pharetra
+ nulla purus posuere arcu.
+
+ Quisque feugiat elit sem, ac interdum diam pharetra nec. Curabitur sem libero, vulputate
+ eu libero vitae, volutpat facilisis ligula. Aenean maximus erat laoreet, interdum ante in,
+ ultrices nisi. Nullam nec efficitur sapien. Integer feugiat et tortor ac bibendum. Donec a
+ scelerisque tortor. Cras quis viverra diam, vitae viverra ipsum. Aliquam ultrices neque sem,
+ congue sodales elit tempus sit amet. Pellentesque habitant morbi tristique senectus et netus
+ et malesuada fames ac turpis egestas. Sed dignissim ipsum eget diam rhoncus, ut finibus
+ nulla pretium. Morbi suscipit nibh vel nisl posuere molestie. Maecenas posuere turpis et
+ rutrum consectetur. Morbi venenatis arcu non gravida vulputate. Vivamus auctor tellus
+ ullamcorper ligula vestibulum cursus. Nunc gravida sit amet nisl quis facilisis.
+
+ Praesent ut justo vestibulum, accumsan mi et, feugiat purus. Nullam pulvinar iaculis
+ pharetra. Aliquam pulvinar risus sit amet elit suscipit tincidunt. In hac habitasse platea
+ dictumst. Etiam eget velit ac magna lacinia efficitur. Vestibulum ante ipsum primis in
+ faucibus orci luctus et ultrices posuere cubilia Curae; Cras volutpat tempus sollicitudin.
+ Ut et ante elit.
+
+ Sed ac tortor justo. Fusce sed metus libero. Duis sagittis tortor ac ante sollicitudin,
+ nec efficitur nibh euismod. Donec porttitor cursus quam, in aliquam lorem feugiat ut.
+ Aliquam tempor lacus eu feugiat feugiat. Nunc pulvinar, libero at auctor commodo, metus diam
+ commodo lorem, in feugiat elit ex non ligula. Quisque at vestibulum sapien, nec facilisis
+ neque. Aenean luctus, arcu ut rhoncus luctus, est massa rhoncus mauris, nec luctus urna sem
+ quis massa. Nam elit felis, congue et ligula eget, ultricies tincidunt erat. Vivamus
+ eleifend no dui ac dictum. In nulla justo, pulvinar ut tristique sed, congue et orci.
+
+ Quisque imperdiet mi lectus, ac scelerisque augue posuere ut. Duis non pulvinar ipsum,
+ finibus risus. Donec ullamcorper nisl at sodales lobortis. Mauris neque leo, vestibulum sit
+ amet placerat vel, aliquet vel sapien. Morbi massa tellus, scelerisque quis nisl in, feugiat
+ posuere augue. Aenean congue sem ut ipsum vulputate rhoncus vitae at eros. Maecenas in velit
+ orci pellentesque lobortis ac at felis. Vestibulum odio quam, lacinia dapibus ornare eu,
+ vulputate a eros. Curabitur eleifend ornare tellus, non sollicitudin justo viverra in. Sed
+ sodales neque et lacus semper, in pharetra est consequat. Nunc vehicula volutpat lectus, sit
+ amet scelerisque nisi. Aenean sollicitudin, sem at ultricies efficitur, eros metus
+ nisl, et fringilla felis lacus non orci. Praesent eros libero, finibus in purus id,
+ tempor ipsum. Donec suscipit libero velit. Aliquam quis diam pharetra, cursus ipsum in,
+ gravida metus. Maecenas ultrices ligula a ullamcorper scelerisque.
+
+ Donec tincidunt felis turpis, id venenatis neque convallis in. Proin euismod ligula nec
+ urna vulputate, sed elementum mauris ultrices. Ut efficitur sem vel mi vestibulum placerat.
+ Sed fermentum lacus nec metus dictum, a commodo quam fermentum. Sed vel vulputate magna.
+ Integer convallis nisi sit amet mi lobortis pellentesque. In egestas porttitor elit eu
+ scelerisque. Suspendisse eleifend vel enim quis tincidunt. Sed placerat risus et pretium
+ porttitor. Nam justo mi, cursus eu pellentesque vel, bibendum ut nisl. Nulla condimentum
+ lorem, non sagittis lorem volutpat vitae. Mauris nec libero lorem. Vestibulum lacus ex,
+ vulputate non massa vitae, pellentesque vestibulum dolor.
+
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+ Suspendisse vitae erat nisl. Vestibulum elit ante, semper et semper sit amet, fringilla
+ sapien. Morbi ac nisi sit amet turpis tincidunt mattis ac eget nisl. Nunc a venenatis quam,
+ facilisis maximus odio. Aliquam erat volutpat. Maecenas leo enim, ornare a magna quis,
+ venenatis ornare nulla. Aliquam venenatis nibh et elit tincidunt, ut egestas lorem finibus.
+ Integer iaculis dolor sed enim blandit vestibulum. Nullam vel libero ultricies, sagittis
+ tortor non, molestie eros.</string>
</resources>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java
new file mode 100644
index 0000000..57d34f8
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ExtraAssistDataActivity.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.assist.testapp;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.assist.common.Utils;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.Override;
+
+/**
+ * Test the onProvideAssistData and onProvideAssistContent methods activities may override to
+ * provide extra information to the assistant. Verify that the data passed from the activity matches
+ * the data received in {@link android.service.voice.VoiceInteractionSession}.
+ */
+public class ExtraAssistDataActivity extends Activity {
+ private static final String TAG = "ExtraAssistDataActivity";
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onProvideAssistData(Bundle data) {
+ super.onProvideAssistData(data);
+ Log.i(TAG, "onProvideAssistData");
+ Utils.addExtraAssistDataToBundle(data);
+ }
+
+ @Override
+ public void onProvideAssistContent(AssistContent outContent) {
+ super.onProvideAssistContent(outContent);
+ Log.i(TAG, "onProvideAssistContent");
+ try {
+ outContent.setStructuredData(Utils.getStructuredJSON());
+ } catch (Exception e) {
+ Log.i(TAG, "Failed to get Structured JSON to put into the AssistContent.");
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
new file mode 100644
index 0000000..4ab24ed
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/FocusChangeActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.testapp;
+
+import android.app.Activity;
+import android.assist.common.Utils;
+import android.content.Intent;
+import android.util.Log;
+
+public class FocusChangeActivity extends Activity {
+ private static final String TAG = "FocusChangeActivity";
+ private boolean mGainedFocus = false;
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ if (hasFocus && !mGainedFocus) {
+ mGainedFocus = true;
+ Log.i(TAG, "gained focus");
+ sendBroadcast(new Intent(Utils.GAINED_FOCUS));
+ } else if (!hasFocus && mGainedFocus) {
+ Log.i(TAG, "lost focus");
+ sendBroadcast(new Intent(Utils.LOST_FOCUS));
+ }
+ }
+}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
index 4e1dc80..af10f99 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
@@ -39,22 +39,22 @@
@Override
protected void onPause() {
- super.onPause();
Log.i(TAG, "activity was paused");
sendBroadcast(new Intent("android.intent.action.lifecycle_onpause"));
+ super.onPause();
}
@Override
protected void onStop() {
- super.onStop();
Log.i(TAG, "activity was stopped");
sendBroadcast(new Intent("android.intent.action.lifecycle_onstop"));
+ super.onStop();
}
@Override
protected void onDestroy() {
- super.onDestroy();
Log.i(TAG, "activity was destroyed");
sendBroadcast(new Intent("android.intent.action.lifecycle_ondestroy"));
+ super.onDestroy();
}
}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java
new file mode 100644
index 0000000..581af2e
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/ScreenshotActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+import java.lang.Override;
+
+public class ScreenshotActivity extends Activity {
+ static final String TAG = "ScreenshotActivity";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.i(TAG, "ScreenshotActivity created");
+ setContentView(R.layout.screenshot_activity);
+ }
+
+ @Override
+ public void onResume() {
+ Log.i(TAG, " in onResume");
+ super.onResume();
+ int backgroundColor = getIntent().getIntExtra(Utils.SCREENSHOT_COLOR_KEY, Color.WHITE);
+ View view = findViewById(R.id.screenshot_activity);
+ view.setBackgroundColor(backgroundColor);
+ view.requestLayout();
+
+ // Tell service activity is in foreground.
+ Intent intent = new Intent(Utils.APP_3P_HASRESUMED);
+ sendBroadcast(intent);
+ Log.i(TAG, "Resumed broadcast sent.");
+ }
+
+ @Override
+ public void onPause() {
+ Log.i(TAG, "onPause");
+ finish();
+ super.onPause();
+ }
+}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
index ff56ea8..e0f83cc 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -20,6 +20,16 @@
import android.app.Activity;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
+import java.io.ByteArrayOutputStream;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -31,12 +41,20 @@
public class TestApp extends Activity {
static final String TAG = "TestApp";
+ private String mTestCaseName;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "TestApp created");
- setContentView(R.layout.test_app);
+ mTestCaseName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+ switch (mTestCaseName) {
+ case Utils.LARGE_VIEW_HIERARCHY:
+ setContentView(R.layout.multiple_text_views);
+ return;
+ default:
+ setContentView(R.layout.test_app);
+ }
}
@Override
@@ -49,7 +67,7 @@
@Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- sendBroadcast(new Intent(Utils.ASSIST_STRUCTURE_HASRESUMED));
+ sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
}
});
}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java
new file mode 100644
index 0000000..9e57e9b
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TextViewActivity.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.lang.Override;
+
+public class TextViewActivity extends Activity {
+ static final String TAG = "TextViewActivity";
+
+ private BroadcastReceiver mReceiver;
+ private TextView mTextView;
+ private ScrollView mScrollView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.i(TAG, "TextViewActivity created");
+ setContentView(R.layout.text_view);
+ mScrollView = (ScrollView) findViewById(R.id.scroll_view);
+ mTextView = (TextView) findViewById(R.id.text_view);
+ mTextView.setMovementMethod(new ScrollingMovementMethod());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Log.i(TAG, "TextViewActivity has resumed");
+
+ mReceiver = new ScrollReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Utils.SCROLL_TEXTVIEW_ACTION);
+ filter.addAction(Utils.SCROLL_SCROLLVIEW_ACTION);
+ registerReceiver(mReceiver, filter);
+
+ final View layout = findViewById(android.R.id.content);
+ ViewTreeObserver vto = layout.getViewTreeObserver();
+ vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ if (mReceiver != null) {
+ unregisterReceiver(mReceiver);
+ }
+ super.onPause();
+ }
+
+ class ScrollReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int scrollX, scrollY;
+ scrollX = intent.getIntExtra(Utils.SCROLL_X_POSITION, 0);
+ scrollY = intent.getIntExtra(Utils.SCROLL_Y_POSITION, 0);
+ if (intent.getAction().equals(Utils.SCROLL_TEXTVIEW_ACTION)) {
+ Log.i(TAG, "Scrolling textview to (" + scrollX + "," + scrollY + ")");
+ if (scrollX < 0 || scrollY < 0) {
+ // Scroll to bottom as negative positions are not possible.
+ scrollX = mTextView.getWidth();
+ scrollY = mTextView.getLayout().getLineTop(mTextView.getLineCount())
+ - mTextView.getHeight();
+ }
+ TextViewActivity.this.mTextView.scrollTo(scrollX, scrollY);
+ } else if (intent.getAction().equals(Utils.SCROLL_SCROLLVIEW_ACTION)) {
+ Log.i(TAG, "Scrolling scrollview to (" + scrollX + "," + scrollY + ")");
+ if (scrollX < 0 || scrollY < 0) {
+ // Scroll to bottom
+ TextViewActivity.this.mScrollView.fullScroll(View.FOCUS_DOWN);
+ TextViewActivity.this.mScrollView.fullScroll(View.FOCUS_RIGHT);
+ } else {
+ TextViewActivity.this.mScrollView.scrollTo(scrollX, scrollY);
+ }
+ }
+ Log.i(TAG, "the max height of this textview is: " + mTextView.getHeight());
+ Log.i(TAG, "the max line count of this text view is: " + mTextView.getMaxLines());
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java
new file mode 100644
index 0000000..59f96cb
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/WebViewActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.testapp;
+
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import java.lang.Override;
+
+public class WebViewActivity extends Activity {
+ static final String TAG = "WebViewActivity";
+
+ private String mTestCaseName;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.i(TAG, "TestApp created");
+ mTestCaseName = getIntent().getStringExtra(Utils.TESTCASE_TYPE);
+ setContentView(R.layout.webview);
+ WebView webview = (WebView) findViewById(R.id.webview);
+ webview.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url){
+ sendBroadcast(new Intent(Utils.APP_3P_HASRESUMED));
+ }
+ });
+ webview.loadData(Utils.WEBVIEW_HTML, "text/html", "UTF-8");
+ //webview.loadUrl(
+ // "https://android-developers.blogspot.com/2015/08/m-developer-preview-3-final-sdk.html");
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index cc444a6..bc819c1 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -41,6 +41,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -58,6 +59,7 @@
private static final int SCAN_DURATION_MILLIS = 5000;
private static final int BATCH_SCAN_REPORT_DELAY_MILLIS = 20000;
+ private CountDownLatch mFlushBatchScanLatch;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mScanner;
@@ -215,8 +217,14 @@
batchScanCallback);
sleep(SCAN_DURATION_MILLIS);
mScanner.flushPendingScanResults(batchScanCallback);
- sleep(1000);
+ mFlushBatchScanLatch = new CountDownLatch(1);
List<ScanResult> results = batchScanCallback.getBatchScanResults();
+ try {
+ mFlushBatchScanLatch.await(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ // Nothing to do.
+ Log.e(TAG, "interrupted!");
+ }
assertTrue(!results.isEmpty());
long scanEndMillis = SystemClock.elapsedRealtime();
mScanner.stopScan(batchScanCallback);
@@ -252,6 +260,9 @@
// In case onBatchScanResults are called due to buffer full, we want to collect all
// scan results.
mBatchScanResults.addAll(results);
+ if (mFlushBatchScanLatch != null) {
+ mFlushBatchScanLatch.countDown();
+ }
}
// Clear regular and batch scan results.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
index 75de9c0..41e2045 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
@@ -714,6 +714,7 @@
// clear out the surface and camera session
stopPreviewAndClearSurface(previewBuilder, rawBurstBuilder);
+ rawReaderListener.drain();
closeImageReader();
}
} finally {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index c5eb27b..d78b3b5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -337,7 +337,7 @@
*
*/
public void drain() {
- for (int i = 0; i < mQueue.size(); i++) {
+ while (!mQueue.isEmpty()) {
Image image = mQueue.poll();
assertNotNull("Unable to get an image", image);
image.close();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 9e75d94..dd4e3e3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -69,7 +69,8 @@
private static final long EXPOSURE_TIME_BOUNDARY_50HZ_NS = 10000000L; // 10ms
private static final long EXPOSURE_TIME_BOUNDARY_60HZ_NS = 8333333L; // 8.3ms, Approximation.
private static final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000L; // 100us, Approximation.
- private static final int SENSITIVITY_ERROR_MARGIN = 10; // 10
+ private static final float EXPOSURE_TIME_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation.
+ private static final float SENSITIVITY_ERROR_MARGIN_RATE = 0.03f; // 3%, Approximation.
private static final int DEFAULT_NUM_EXPOSURE_TIME_STEPS = 3;
private static final int DEFAULT_NUM_SENSITIVITY_STEPS = 16;
private static final int DEFAULT_SENSITIVITY_STEP_SIZE = 100;
@@ -1711,9 +1712,10 @@
// video stabilization test.
List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys();
- int[] videoStabModes = (keys.contains(CameraCharacteristics.
+ Integer[] videoStabModes = (keys.contains(CameraCharacteristics.
CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) ?
- mStaticInfo.getAvailableVideoStabilizationModesChecked() : new int[0];
+ CameraTestUtils.toObject(mStaticInfo.getAvailableVideoStabilizationModesChecked()) :
+ new Integer[0];
int[] opticalStabModes = (keys.contains(
CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) ?
mStaticInfo.getAvailableOpticalStabilizationChecked() : new int[0];
@@ -1724,13 +1726,14 @@
SimpleCaptureCallback listener = new SimpleCaptureCallback();
startPreview(requestBuilder, maxPreviewSize, listener);
- for (int mode : videoStabModes) {
+ for (Integer mode : videoStabModes) {
listener = new SimpleCaptureCallback();
requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, mode);
mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
- verifyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE, mode,
- listener, NUM_FRAMES_VERIFIED);
+ // Video stabilization could return any modes.
+ verifyAnyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE,
+ videoStabModes, listener, NUM_FRAMES_VERIFIED);
}
for (int mode : opticalStabModes) {
@@ -2093,10 +2096,12 @@
*/
private void validateExposureTime(long request, long result) {
long expTimeDelta = request - result;
+ long expTimeErrorMargin = (long)(Math.max(EXPOSURE_TIME_ERROR_MARGIN_NS, request
+ * EXPOSURE_TIME_ERROR_MARGIN_RATE));
// First, round down not up, second, need close enough.
mCollector.expectTrue("Exposture time is invalid for AE manaul control test, request: "
+ request + " result: " + result,
- expTimeDelta < EXPOSURE_TIME_ERROR_MARGIN_NS && expTimeDelta >= 0);
+ expTimeDelta < expTimeErrorMargin && expTimeDelta >= 0);
}
/**
@@ -2106,11 +2111,12 @@
* @param result Result sensitivity
*/
private void validateSensitivity(int request, int result) {
- int sensitivityDelta = request - result;
+ float sensitivityDelta = (float)(request - result);
+ float sensitivityErrorMargin = request * SENSITIVITY_ERROR_MARGIN_RATE;
// First, round down not up, second, need close enough.
mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: "
+ request + " result: " + result,
- sensitivityDelta < SENSITIVITY_ERROR_MARGIN && sensitivityDelta >= 0);
+ sensitivityDelta < sensitivityErrorMargin && sensitivityDelta >= 0);
}
/**
@@ -2158,6 +2164,30 @@
}
/**
+ * Basic verification that the value of a capture result key should be one of the expected
+ * values.
+ *
+ * @param key The capture result key to be verified against
+ * @param expectedModes The list of any possible expected modes for this result
+ * @param listener The capture listener to get capture results
+ * @param numFramesVerified The number of capture results to be verified
+ */
+ private <T> void verifyAnyCaptureResultForKey(CaptureResult.Key<T> key, T[] expectedModes,
+ SimpleCaptureCallback listener, int numFramesVerified) {
+ for (int i = 0; i < numFramesVerified; i++) {
+ CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+ validatePipelineDepth(result);
+ T resultMode = getValueNotNull(result, key);
+ if (VERBOSE) {
+ Log.v(TAG, "Expect values: " + Arrays.toString(expectedModes) + " result value: "
+ + resultMode.toString());
+ }
+ // Capture result should be one of the expected values.
+ mCollector.expectContains(expectedModes, resultMode);
+ }
+ }
+
+ /**
* Verify if the fps is slow down for given input request with certain
* controls inside.
* <p>
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
index dc499ba..2ae29c3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -316,18 +316,24 @@
session, previewBuilder.build(), mHandler);
// Check if all timestamps are the same
+ Image prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateTimestamps("Result 1", result.first,
- prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result.second);
+ prevImage, result.second);
+ prevImage.close();
// Capture targeting both jpeg and preview
Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback,
session, multiBuilder.build(), mHandler);
// Check if all timestamps are the same
+ prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+ Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateTimestamps("Result 2 Preview", result2.first,
- prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+ prevImage, result2.second);
validateTimestamps("Result 2 Jpeg", result2.first,
- jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
+ jpegImage, result2.second);
+ prevImage.close();
+ jpegImage.close();
// Check if timestamps are increasing
mCollector.expectGreater("Timestamps must be increasing.", result.second,
@@ -343,10 +349,14 @@
long resultDiff = result4.second - result3.second;
// Check if all timestamps are the same
+ prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateTimestamps("Result 3", result3.first,
- prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result3.second);
+ prevImage, result3.second);
+ prevImage.close();
+ prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateTimestamps("Result 4", result4.first,
- prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result4.second);
+ prevImage, result4.second);
+ prevImage.close();
// Check that the timestamps monotonically increase at a reasonable rate
mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.",
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 7c80c7d..f1115c4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -460,6 +460,10 @@
// Stop capture, delete the streams.
stopCapture(/*fast*/false);
+ yuvImage.close();
+ jpegImage.close();
+ yuvListener.drain();
+ jpegListener.drain();
} finally {
closeImageReader(jpegReader);
jpegReader = null;
@@ -645,6 +649,8 @@
maxYuvSz.getHeight(), ImageFormat.YUV_420_888, /*filePath*/null);
CameraTestUtils.validateImage(captureImage, captureSz.getWidth(),
captureSz.getHeight(), format, /*filePath*/null);
+ yuvImage.close();
+ captureImage.close();
}
// Stop capture, delete the streams.
@@ -788,7 +794,7 @@
getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME),
TEST_EXPOSURE_TIME_NS),
exposureTimeDiff < EXPOSURE_TIME_ERROR_MARGIN_NS &&
- exposureTimeDiff > 0);
+ exposureTimeDiff >= 0);
mCollector.expectTrue(
String.format("Long processing frame %d format %d size %s " +
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
index dfba587..2795bde 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -78,7 +78,7 @@
Exception prior = null;
ImageVerifierListener yuvListener;
- ImageReader yuvReader;
+ ImageReader yuvReader = null;
try {
openCamera(cameraId);
@@ -102,6 +102,9 @@
prior = e;
} finally {
try {
+ if (yuvReader != null) {
+ yuvReader.close();
+ }
closeCamera(cameraId);
} catch (Exception e) {
if (prior != null) {
@@ -151,7 +154,7 @@
Exception prior = null;
ImageVerifierListener yuvListener;
- ImageReader yuvReader;
+ ImageReader yuvReader = null;
try {
openCamera(cameraId);
@@ -175,6 +178,9 @@
prior = e;
} finally {
try {
+ if (yuvReader != null) {
+ yuvReader.close();
+ }
closeCamera(cameraId);
} catch (Exception e) {
if (prior != null) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
index 4af88ca..39eb1dc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -66,13 +66,12 @@
private static final int NUM_MAX_IMAGES = 4;
private static final int NUM_RESULTS_WAIT = 30;
private static final int[] REPROCESS_FORMATS = {ImageFormat.YUV_420_888, ImageFormat.PRIVATE};
- private final int MAX_REPROCESS_IMAGES = 10;
+ private final int MAX_REPROCESS_IMAGES = 6;
private final int MAX_JPEG_IMAGES = MAX_REPROCESS_IMAGES;
private final int MAX_INPUT_IMAGES = MAX_REPROCESS_IMAGES;
// ZSL queue depth should be bigger than the max simultaneous reprocessing capture request
// count to maintain reasonable number of candidate image for the worse-case.
- // Here we want to make sure we at most dequeue half of the queue max images for the worst-case.
- private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 2;
+ private final int MAX_ZSL_IMAGES = MAX_REPROCESS_IMAGES * 3 / 2;
private final double REPROCESS_STALL_MARGIN = 0.1;
private DeviceReportLog mReportLog;
@@ -434,7 +433,7 @@
// Wait for reprocess output jpeg and result come back.
reprocessResultListener.getCaptureResultForRequest(reprocessRequest,
CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
- mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+ mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
long numFramesMaybeStalled = mZslResultListener.getTotalNumFrames();
assertTrue("Reprocess capture result should be returned in "
+ MAX_REPROCESS_RETURN_FRAME_COUNT + " frames",
@@ -475,6 +474,8 @@
maxCaptureGapsMs[i] = maxTimestampGapMs;
}
+ stopZslStreaming();
+
String reprocessType = " YUV reprocessing ";
if (reprocessInputFormat == ImageFormat.PRIVATE) {
reprocessType = " opaque reprocessing ";
@@ -539,24 +540,34 @@
// Get images
startTimeMs = SystemClock.elapsedRealtime();
+ Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
- mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+ jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
startTimeMs = SystemClock.elapsedRealtime();
}
+ for (Image i : jpegImages) {
+ i.close();
+ }
} else {
// sync capture: issue reprocess request one by one, only submit next one when
// the previous capture image is returned. This is to test the back to back capture
// performance.
+ Image jpegImages[] = new Image[MAX_REPROCESS_IMAGES];
for (int i = 0; i < MAX_REPROCESS_IMAGES; i++) {
startTimeMs = SystemClock.elapsedRealtime();
mWriter.queueInputImage(inputImages[i]);
mSession.capture(reprocessReqs[i].build(), null, null);
- mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+ jpegImages[i] = mJpegListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
getImageLatenciesMs[i] = SystemClock.elapsedRealtime() - startTimeMs;
}
+ for (Image i : jpegImages) {
+ i.close();
+ }
}
+ stopZslStreaming();
+
String reprocessType = " YUV reprocessing ";
if (reprocessInputFormat == ImageFormat.PRIVATE) {
reprocessType = " opaque reprocessing ";
@@ -591,6 +602,12 @@
mSession.setRepeatingRequest(zslBuilder.build(), mZslResultListener, mHandler);
}
+ private void stopZslStreaming() throws Exception {
+ mSession.stopRepeating();
+ mSessionListener.getStateWaiter().waitForState(
+ BlockingSessionCallback.SESSION_READY, CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
+ }
+
/**
* Wait for a certain number of frames, the images and results will be drained from the
* listeners to make sure that next reprocessing can get matched results and images.
@@ -598,24 +615,22 @@
* @param numFrameWait The number of frames to wait before return, 0 means that
* this call returns immediately after streaming on.
*/
- private void waitForFrames(int numFrameWait) {
+ private void waitForFrames(int numFrameWait) throws Exception {
if (numFrameWait < 0) {
throw new IllegalArgumentException("numFrameWait " + numFrameWait +
" should be non-negative");
}
- if (numFrameWait == 0) {
- // Let is stream out for a while
- waitForNumResults(mZslResultListener, numFrameWait);
- // Drain the pending images, to ensure that all future images have an associated
- // capture result available.
- mCameraZslImageListener.drain();
+ for (int i = 0; i < numFrameWait; i++) {
+ mCameraZslImageListener.getImage(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS).close();
}
}
private void closeReaderWriters() {
+ mCameraZslImageListener.drain();
CameraTestUtils.closeImageReader(mCameraZslReader);
mCameraZslReader = null;
+ mJpegListener.drain();
CameraTestUtils.closeImageReader(mJpegReader);
mJpegReader = null;
CameraTestUtils.closeImageWriter(mWriter);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 52fd69f..de0e3d5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -14,6 +14,7 @@
import static android.hardware.camera2.cts.CameraTestUtils.*;
import static com.android.ex.camera2.blocking.BlockingSessionCallback.*;
+import android.cts.util.MediaUtils;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraCaptureSession;
@@ -151,6 +152,9 @@
* </p>
*/
public void testRecordingFromPersistentSurface() throws Exception {
+ if (!MediaUtils.checkCodecForDomain(true /* encoder */, "video")) {
+ return; // skipped
+ }
mPersistentSurface = MediaCodec.createPersistentInputSurface();
assertNotNull("Failed to create persistent input surface!", mPersistentSurface);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
index 8a60dc2..dd49c8d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
@@ -1211,6 +1211,9 @@
throw new IllegalArgumentException("isReprocessCaptures must have at least 1 capture.");
}
+ boolean hasReprocessRequest = false;
+ boolean hasRegularRequest = false;
+
TotalCaptureResult[] results = new TotalCaptureResult[isReprocessCaptures.length];
for (int i = 0; i < isReprocessCaptures.length; i++) {
// submit a capture and get the result if this entry is a reprocess capture.
@@ -1219,6 +1222,9 @@
/*inputResult*/null);
mImageWriter.queueInputImage(
mFirstImageReaderListener.getImage(CAPTURE_TIMEOUT_MS));
+ hasReprocessRequest = true;
+ } else {
+ hasRegularRequest = true;
}
}
@@ -1232,7 +1238,24 @@
ImageResultHolder[] holders = new ImageResultHolder[isReprocessCaptures.length];
for (int i = 0; i < isReprocessCaptures.length; i++) {
Image image = getReprocessOutputImageReaderListener().getImage(CAPTURE_TIMEOUT_MS);
- holders[i] = new ImageResultHolder(image, finalResults[i]);
+ if (hasReprocessRequest && hasRegularRequest) {
+ // If there are mixed requests, images and results may not be in the same order.
+ for (int j = 0; j < finalResults.length; j++) {
+ if (finalResults[j] != null &&
+ finalResults[j].get(CaptureResult.SENSOR_TIMESTAMP) ==
+ image.getTimestamp()) {
+ holders[i] = new ImageResultHolder(image, finalResults[j]);
+ finalResults[j] = null;
+ break;
+ }
+ }
+
+ assertNotNull("Cannot find a result matching output image's timestamp: " +
+ image.getTimestamp(), holders[i]);
+ } else {
+ // If no mixed requests, images and results should be in the same order.
+ holders[i] = new ImageResultHolder(image, finalResults[i]);
+ }
}
return holders;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
index 8ccc931..ddae8eb 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -1351,8 +1351,8 @@
Log.i(TAG, String.format("Testing Camera %s, config %s",
cameraId, MaxStreamSizes.configToString(config)));
- // Timeout is relaxed by 500ms for LEGACY devices to reduce false positive rate in CTS
- final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 1500 : 1000;
+ // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
+ final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
final int MIN_RESULT_COUNT = 3;
// Set up outputs
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index 68efef0..a2ddb4d 100755
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -105,7 +105,7 @@
if (supports64Bit) {
assertMinMemoryMb(1824);
} else {
- assertMinMemoryMb(1344);
+ assertMinMemoryMb(1099);
}
} else if (greaterThanDpi(density, DENSITY_400, screenSize,
SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
index c807e03..22f092a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -102,13 +102,13 @@
sensor.getMaximumRange() >= maxRange);
double actualMinFrequency = SensorCtsHelper.getFrequency(sensor.getMaxDelay(),
TimeUnit.MICROSECONDS);
- assertTrue(String.format("%s Min Frequency actual=%.2f expected=%dHz",
+ assertTrue(String.format("%s Min Frequency actual=%.2f expected=%.2fHz",
sensor.getName(), actualMinFrequency, minFrequency), actualMinFrequency <=
minFrequency + 0.1);
double actualMaxFrequency = SensorCtsHelper.getFrequency(sensor.getMinDelay(),
TimeUnit.MICROSECONDS);
- assertTrue(String.format("%s Max Frequency actual=%.2f expected=%dHz",
+ assertTrue(String.format("%s Max Frequency actual=%.2f expected=%.2fHz",
sensor.getName(), actualMaxFrequency, maxFrequency), actualMaxFrequency >=
maxFrequency - 0.1);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 2c3c6f4..cffafdc 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -88,7 +88,7 @@
}
@Override
- protected void tearDown(){
+ protected void tearDown() {
if (mSensorManager != null) {
// SensorManager will check listener and status, so just unregister listener
mSensorManager.unregisterListener(mNullSensorEventListener);
@@ -256,7 +256,8 @@
if (mTriggerSensor == null) {
throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
}
- boolean result = mSensorManager.requestTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
+ boolean result =
+ mSensorManager.requestTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
assertFalse(result);
}
@@ -265,7 +266,8 @@
if (mTriggerSensor == null) {
throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
}
- boolean result = mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
+ boolean result =
+ mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
assertFalse(result);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
index 55465ac..9cb3710 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -38,21 +38,32 @@
private SensorCtsHelper() {}
/**
- * Get the value of the 95th percentile using nearest rank algorithm.
+ * Get percentiles using nearest rank algorithm.
*
- * @throws IllegalArgumentException if the collection is null or empty
+ * @param percentiles List of percentiles interested. Its range is 0 to 1, instead of in %.
+ * The value will be internally bounded.
+ *
+ * @throws IllegalArgumentException if the collection or percentiles is null or empty
*/
- public static <TValue extends Comparable<? super TValue>> TValue get95PercentileValue(
- Collection<TValue> collection) {
+ public static <TValue extends Comparable<? super TValue>> List<TValue> getPercentileValue(
+ Collection<TValue> collection, float[] percentiles) {
validateCollection(collection);
+ if(percentiles == null || percentiles.length == 0) {
+ throw new IllegalStateException("percentiles cannot be null or empty");
+ }
List<TValue> arrayCopy = new ArrayList<TValue>(collection);
Collections.sort(arrayCopy);
- // zero-based array index
- int arrayIndex = (int) Math.round(arrayCopy.size() * 0.95 + .5) - 1;
-
- return arrayCopy.get(arrayIndex);
+ List<TValue> percentileValues = new ArrayList<TValue>();
+ for (float p : percentiles) {
+ // zero-based array index
+ int arrayIndex = (int) Math.round(arrayCopy.size() * p - .5f);
+ // bound the index to avoid out of range error
+ arrayIndex = Math.min(Math.max(arrayIndex, 0), arrayCopy.size() - 1);
+ percentileValues.add(arrayCopy.get(arrayIndex));
+ }
+ return percentileValues;
}
/**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 3e70e75..e8df1ab 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -172,8 +172,7 @@
*/
public List<TestSensorEvent> getCollectedEvents() {
synchronized (mCollectedEvents){
- List<TestSensorEvent> collectedEventsList = (List)mCollectedEvents.clone();
- return Collections.unmodifiableList(collectedEventsList);
+ return Collections.unmodifiableList((List<TestSensorEvent>) mCollectedEvents.clone());
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
index d246ec5..9d36f37 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
@@ -16,8 +16,6 @@
package android.hardware.cts.helpers.sensorverification;
-import junit.framework.Assert;
-
import android.content.Context;
import android.content.pm.PackageManager;
@@ -34,6 +32,7 @@
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import junit.framework.Assert;
/**
* A {@link ISensorVerification} which verifies that the sensor jitter is in an acceptable range.
@@ -43,15 +42,22 @@
// sensorType: threshold (% of expected period)
private static final SparseIntArray DEFAULTS = new SparseIntArray(12);
- // Max allowed jitter (in percentage).
+ // Max allowed jitter in +/- sense (in percentage).
private static final int GRACE_FACTOR = 2;
private static final int THRESHOLD_PERCENT_FOR_HIFI_SENSORS = 1 * GRACE_FACTOR;
+
+ // Margin sample intervals that considered outliers, lower and higher margin is discarded
+ // before verification
+ private static final float OUTLIER_MARGIN = 0.025f; //2.5%
+
static {
// Use a method so that the @deprecation warning can be set for that method only
setDefaults();
}
- private final int mThresholdAsPercentage;
+ private final float mOutlierMargin;
+ private final long mThresholdNs;
+ private final long mExpectedPeriodNs; // for error message only
private final List<Long> mTimestamps = new LinkedList<Long>();
/**
@@ -59,8 +65,10 @@
*
* @param thresholdAsPercentage the acceptable margin of error as a percentage
*/
- public JitterVerification(int thresholdAsPercentage) {
- mThresholdAsPercentage = thresholdAsPercentage;
+ public JitterVerification(float outlierMargin, long thresholdNs, long expectedPeriodNs) {
+ mExpectedPeriodNs = expectedPeriodNs;
+ mOutlierMargin = outlierMargin;
+ mThresholdNs = thresholdNs;
}
/**
@@ -71,16 +79,20 @@
*/
public static JitterVerification getDefault(TestSensorEnvironment environment) {
int sensorType = environment.getSensor().getType();
- int threshold = DEFAULTS.get(sensorType, -1);
- if (threshold == -1) {
+
+ int thresholdPercent = DEFAULTS.get(sensorType, -1);
+ if (thresholdPercent == -1) {
return null;
}
boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_HIFI_SENSORS);
if (hasHifiSensors) {
- threshold = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
+ thresholdPercent = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
}
- return new JitterVerification(threshold);
+
+ long expectedPeriodNs = (long) environment.getExpectedSamplingPeriodUs() * 1000;
+ long jitterThresholdNs = expectedPeriodNs * thresholdPercent * 2 / 100; // *2 is for +/-
+ return new JitterVerification(OUTLIER_MARGIN, jitterThresholdNs, expectedPeriodNs);
}
/**
@@ -99,24 +111,33 @@
return;
}
- List<Double> jitters = getJitterValues();
- double jitter95PercentileNs = SensorCtsHelper.get95PercentileValue(jitters);
- long firstTimestamp = mTimestamps.get(0);
- long lastTimestamp = mTimestamps.get(timestampsCount - 1);
- long measuredPeriodNs = (lastTimestamp - firstTimestamp) / (timestampsCount - 1);
- double jitter95PercentilePercent = (jitter95PercentileNs * 100.0) / measuredPeriodNs;
- stats.addValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY, jitter95PercentilePercent);
+ List<Long> deltas = getDeltaValues();
+ float percentiles[] = new float[2];
+ percentiles[0] = mOutlierMargin;
+ percentiles[1] = 1 - percentiles[0];
- boolean success = (jitter95PercentilePercent < mThresholdAsPercentage);
+ List<Long> percentileValues = SensorCtsHelper.getPercentileValue(deltas, percentiles);
+ double normalizedRange =
+ (double)(percentileValues.get(1) - percentileValues.get(0)) / mThresholdNs;
+
+ double percentageJitter =
+ (double)(percentileValues.get(1) - percentileValues.get(0)) /
+ mExpectedPeriodNs / 2 * 100; //one side variation comparing to sample time
+
+ stats.addValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY, percentageJitter);
+
+ boolean success = normalizedRange <= 1.0;
stats.addValue(PASSED_KEY, success);
if (!success) {
String message = String.format(
- "Jitter out of range: measured period=%dns, jitter(95th percentile)=%.2f%%"
- + " (expected < %d%%)",
- measuredPeriodNs,
- jitter95PercentilePercent,
- mThresholdAsPercentage);
+ "Jitter out of range: requested period = %dns, " +
+ "jitter min, max, range (95th percentile) = (%dns, %dns, %dns), " +
+ "jitter expected range <= %dns",
+ mExpectedPeriodNs,
+ percentileValues.get(0), percentileValues.get(1),
+ percentileValues.get(1) - percentileValues.get(0),
+ mThresholdNs);
Assert.fail(message);
}
}
@@ -126,7 +147,7 @@
*/
@Override
public JitterVerification clone() {
- return new JitterVerification(mThresholdAsPercentage);
+ return new JitterVerification(mOutlierMargin, mThresholdNs, mExpectedPeriodNs);
}
/**
@@ -138,19 +159,14 @@
}
/**
- * Get the list of all jitter values. Exposed for unit testing.
+ * Get the list of delta values. Exposed for unit testing.
*/
- List<Double> getJitterValues() {
+ List<Long> getDeltaValues() {
List<Long> deltas = new ArrayList<Long>(mTimestamps.size() - 1);
for (int i = 1; i < mTimestamps.size(); i++) {
deltas.add(mTimestamps.get(i) - mTimestamps.get(i - 1));
}
- double deltaMean = StatisticsUtils.getMean(deltas);
- List<Double> jitters = new ArrayList<Double>(deltas.size());
- for (long delta : deltas) {
- jitters.add(Math.abs(delta - deltaMean));
- }
- return jitters;
+ return deltas;
}
@SuppressWarnings("deprecation")
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
index 50e288c..d8e1586 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
@@ -27,11 +27,10 @@
import java.util.List;
/**
- * Tests for {@link EventOrderingVerification}.
+ * Tests for {@link JitterVerification}.
*/
public class JitterVerificationTest extends TestCase {
-
public void testVerify() {
final int SAMPLE_SIZE = 100;
// for unit testing the verification, only the parameter 'sensorMightHaveMoreListeners' is
@@ -67,54 +66,58 @@
} catch (AssertionError e) {
// Expected;
}
- verifyStats(stats, false, 47.34);
+ verifyStats(stats, false, 25); // 500 us range (250 us in single-sided sense)
+ // divide by 1ms requested sample time x 100%
}
- public void testCalculateJitter() {
+ public void testCalculateDelta() {
long[] timestamps = new long[]{0, 1, 2, 3, 4};
JitterVerification verification = getVerification(1, timestamps);
- List<Double> jitterValues = verification.getJitterValues();
- assertEquals(4, jitterValues.size());
- assertEquals(0.0, jitterValues.get(0));
- assertEquals(0.0, jitterValues.get(1));
- assertEquals(0.0, jitterValues.get(2));
- assertEquals(0.0, jitterValues.get(3));
+ List<Long> deltaValues = verification.getDeltaValues();
+ assertEquals(4, deltaValues.size());
+ assertEquals(1, deltaValues.get(0).longValue());
+ assertEquals(1, deltaValues.get(1).longValue());
+ assertEquals(1, deltaValues.get(2).longValue());
+ assertEquals(1, deltaValues.get(3).longValue());
timestamps = new long[]{0, 0, 2, 4, 4};
verification = getVerification(1, timestamps);
- jitterValues = verification.getJitterValues();
- assertEquals(4, jitterValues.size());
- assertEquals(1.0, jitterValues.get(0));
- assertEquals(1.0, jitterValues.get(1));
- assertEquals(1.0, jitterValues.get(2));
- assertEquals(1.0, jitterValues.get(3));
+ deltaValues = verification.getDeltaValues();
+ assertEquals(4, deltaValues.size());
+ assertEquals(0, deltaValues.get(0).longValue());
+ assertEquals(2, deltaValues.get(1).longValue());
+ assertEquals(2, deltaValues.get(2).longValue());
+ assertEquals(0, deltaValues.get(3).longValue());
timestamps = new long[]{0, 1, 4, 9, 16};
verification = getVerification(1, timestamps);
- jitterValues = verification.getJitterValues();
- assertEquals(4, jitterValues.size());
- assertEquals(4, jitterValues.size());
- assertEquals(3.0, jitterValues.get(0));
- assertEquals(1.0, jitterValues.get(1));
- assertEquals(1.0, jitterValues.get(2));
- assertEquals(3.0, jitterValues.get(3));
+ deltaValues = verification.getDeltaValues();
+ assertEquals(4, deltaValues.size());
+ assertEquals(1, deltaValues.get(0).longValue());
+ assertEquals(3, deltaValues.get(1).longValue());
+ assertEquals(5, deltaValues.get(2).longValue());
+ assertEquals(7, deltaValues.get(3).longValue());
}
- private static JitterVerification getVerification(int threshold, long ... timestamps) {
+ private static JitterVerification getVerification(int marginPercent, long ... timestamps) {
Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
events.add(new TestSensorEvent(null, timestamp, 0, null));
}
- JitterVerification verification = new JitterVerification(threshold);
+ long samplePeriodNs = 1000*1000; //1000Hz
+ long jitterThresholdNs = 20*1000; // 2% of that
+
+ JitterVerification verification =
+ new JitterVerification(marginPercent/100.0f, jitterThresholdNs, samplePeriodNs);
verification.addSensorEvents(events);
return verification;
}
- private void verifyStats(SensorStats stats, boolean passed, double jitter95) {
+ private void verifyStats(SensorStats stats, boolean passed, double percentageJitter) {
assertEquals(passed, stats.getValue(JitterVerification.PASSED_KEY));
assertEquals(
- jitter95,
+ percentageJitter,
(Double) stats.getValue(SensorStats.JITTER_95_PERCENTILE_PERCENT_KEY),
- 0.1);
+ 0.01);
}
}
diff --git a/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4 b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
new file mode 100644
index 0000000..110c0d6
--- /dev/null
+++ b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
old mode 100644
new mode 100755
index b837dc2..f88fe7a
--- a/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
+++ b/tests/tests/media/res/raw/video_1920x1080_mp4_h264_20480kbps_60fps_aac_stereo_128kbps_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 4c03183..9ae6b64 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1646,6 +1646,7 @@
Thread.sleep(WAIT_MSEC); // wait for the data to drain.
// -------- tear down --------------
track.release();
+ Thread.sleep(WAIT_MSEC); // wait for release to complete
frequency += 50; // increment test tone frequency
}
}
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 9da229c..8650d20 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -20,6 +20,8 @@
import android.content.res.AssetFileDescriptor;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
@@ -1141,4 +1143,87 @@
private static String getMimeTypeFor(MediaFormat format) {
return format.getString(MediaFormat.KEY_MIME);
}
+
+ /**
+ * Returns the first codec capable of encoding the specified MIME type, or null if no match was
+ * found.
+ */
+ private static MediaCodecInfo selectCodec(String mimeType) {
+ int numCodecs = MediaCodecList.getCodecCount();
+ for (int i = 0; i < numCodecs; i++) {
+ MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
+
+ if (!codecInfo.isEncoder()) {
+ continue;
+ }
+
+ String[] types = codecInfo.getSupportedTypes();
+ for (int j = 0; j < types.length; j++) {
+ if (types[j].equalsIgnoreCase(mimeType)) {
+ return codecInfo;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the given resolution is supported by the AVC codec.
+ */
+ private static boolean isAvcSupportedSize(int width, int height) {
+ MediaCodecInfo mediaCodecInfo = selectCodec(OUTPUT_VIDEO_MIME_TYPE);
+ CodecCapabilities cap = mediaCodecInfo.getCapabilitiesForType(OUTPUT_VIDEO_MIME_TYPE);
+ if (cap == null) { // not supported
+ return false;
+ }
+ int highestLevel = 0;
+ for (CodecProfileLevel lvl : cap.profileLevels) {
+ if (lvl.level > highestLevel) {
+ highestLevel = lvl.level;
+ }
+ }
+ int maxW = 0;
+ int maxH = 0;
+ int bitRate = 0;
+ int fps = 0; // frame rate for the max resolution
+ switch(highestLevel) {
+ // Do not support Level 1 to 2.
+ case CodecProfileLevel.AVCLevel1:
+ case CodecProfileLevel.AVCLevel11:
+ case CodecProfileLevel.AVCLevel12:
+ case CodecProfileLevel.AVCLevel13:
+ case CodecProfileLevel.AVCLevel1b:
+ case CodecProfileLevel.AVCLevel2:
+ return false;
+ case CodecProfileLevel.AVCLevel21:
+ maxW = 352;
+ maxH = 576;
+ break;
+ case CodecProfileLevel.AVCLevel22:
+ maxW = 720;
+ maxH = 480;
+ break;
+ case CodecProfileLevel.AVCLevel3:
+ maxW = 720;
+ maxH = 480;
+ break;
+ case CodecProfileLevel.AVCLevel31:
+ maxW = 1280;
+ maxH = 720;
+ break;
+ case CodecProfileLevel.AVCLevel32:
+ maxW = 1280;
+ maxH = 720;
+ break;
+ case CodecProfileLevel.AVCLevel4: // only try up to 1080p
+ default:
+ maxW = 1920;
+ maxH = 1080;
+ break;
+ }
+ if(maxW*maxH < width*height)
+ return false;
+ else
+ return true;
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/JetPlayerTest.java b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
index fc03bcc..4df3555 100644
--- a/tests/tests/media/src/android/media/cts/JetPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
@@ -55,6 +55,10 @@
@Override
protected void tearDown() throws Exception {
+ // Prevent tests from failing with EAS_ERROR_FILE_ALREADY_OPEN
+ // after a previous test fails.
+ mJetPlayer.closeJetFile();
+
File jetFile = new File(mJetFile);
if (jetFile.exists()) {
jetFile.delete();
@@ -63,31 +67,32 @@
}
public void testLoadJetFromPath() throws Throwable {
- mJetPlayer.clearQueue();
+ assertTrue(mJetPlayer.clearQueue());
prepareFile();
mJetPlayer.setEventListener(mOnJetEventListener);
- mJetPlayer.loadJetFile(mJetFile);
+ assertTrue(mJetPlayer.loadJetFile(mJetFile));
runJet();
}
public void testLoadJetFromFd() throws Throwable {
- mJetPlayer.clearQueue();
+ assertTrue(mJetPlayer.clearQueue());
mJetPlayer.setEventListener(mOnJetEventListener, mHandler);
- mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet));
+ assertTrue(mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet)));
runJet();
}
public void testQueueJetSegmentMuteArray() throws Throwable {
- mJetPlayer.clearQueue();
+ assertTrue(mJetPlayer.clearQueue());
mJetPlayer.setEventListener(mOnJetEventListener, mHandler);
- mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet));
+ assertTrue(mJetPlayer.loadJetFile(mContext.getResources().openRawResourceFd(R.raw.test_jet)));
byte userID = 0;
int segmentNum = 3;
int libNum = -1;
int repeatCount = 0;
int transpose = 0;
boolean[] muteFlags = new boolean[32];
- assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, transpose,
+ assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum,
+ repeatCount, transpose,
muteFlags, userID));
assertTrue(mJetPlayer.play());
for (int i = 0; i < muteFlags.length; i++) {
@@ -96,7 +101,8 @@
muteFlags[8] = false;
muteFlags[9] = false;
muteFlags[10] = false;
- assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, transpose,
+ assertTrue(mJetPlayer.queueJetSegmentMuteArray(segmentNum, libNum,
+ repeatCount, transpose,
muteFlags, userID));
Thread.sleep(20000);
assertTrue(mJetPlayer.pause());
@@ -112,16 +118,19 @@
int repeatCount = 1;
int transpose = 0;
int muteFlags = 0;
- mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+ assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+ transpose, muteFlags, userID));
segmentNum = 6;
repeatCount = 1;
transpose = -1;
- mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+ assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+ transpose, muteFlags, userID));
segmentNum = 7;
transpose = 0;
- mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+ assertTrue(mJetPlayer.queueJetSegment(segmentNum, libNum, repeatCount,
+ transpose, muteFlags, userID));
for (int i = 0; i < 7; i++) {
assertTrue(mJetPlayer.triggerClip(i));
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 813af0f2..71cbd61 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -600,6 +600,29 @@
return actualMax;
}
+ private boolean knownTypes(String type) {
+ return (type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC3 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_OPUS ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_VORBIS ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG2 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8 ) ||
+ type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9 ));
+ }
+
public void testGetMaxSupportedInstances() {
final int MAX_INSTANCES = 32;
StringBuilder xmlOverrides = new StringBuilder();
@@ -610,6 +633,10 @@
String[] types = info.getSupportedTypes();
for (int j = 0; j < types.length; ++j) {
+ if (!knownTypes(types[j])) {
+ Log.d(TAG, "skipping unknown type " + types[j]);
+ continue;
+ }
Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
CodecCapabilities caps = info.getCapabilitiesForType(types[j]);
int max = caps.getMaxSupportedInstances();
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index f844b76..75a5a13 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -21,6 +21,7 @@
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.cts.util.MediaUtils;
+import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaDataSource;
@@ -49,6 +50,7 @@
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.Vector;
@@ -95,6 +97,10 @@
}
}
+ public void testonInputBufferFilledSigsegv() throws Exception {
+ testIfMediaServerDied(R.raw.on_input_buffer_filled_sigsegv);
+ }
+
public void testFlacHeapOverflow() throws Exception {
testIfMediaServerDied(R.raw.heap_oob_flac);
}
@@ -105,6 +111,7 @@
public boolean onError(MediaPlayer mp, int what, int extra) {
assertTrue(mp == mMediaPlayer);
assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ Log.w(LOG_TAG, "onError " + what);
return false;
}
});
@@ -120,10 +127,17 @@
AssetFileDescriptor afd = mResources.openRawResourceFd(res);
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
- mMediaPlayer.prepare();
- mMediaPlayer.start();
- mOnCompletionCalled.waitForSignal();
- mMediaPlayer.release();
+ try {
+ mMediaPlayer.prepare();
+ mMediaPlayer.start();
+ if (!mOnCompletionCalled.waitForSignal(5000)) {
+ Log.w(LOG_TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "playback failed", e);
+ } finally {
+ mMediaPlayer.release();
+ }
}
// Bug 13652927
@@ -731,7 +745,7 @@
public void testVideoSurfaceResetting() throws Exception {
final int tolerance = 150;
final int audioLatencyTolerance = 1000; /* covers audio path latency variability */
- final int seekPos = 5000;
+ final int seekPos = 4760; // This is the I-frame position
final CountDownLatch seekDone = new CountDownLatch(1);
@@ -753,7 +767,12 @@
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder2());
int posAfter = mMediaPlayer.getCurrentPosition();
- assertEquals(posAfter, posBefore, tolerance);
+ /* temporarily disable timestamp checking because MediaPlayer now seeks to I-frame
+ * position, instead of requested position. setDisplay invovles a seek operation
+ * internally.
+ */
+ // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+ // assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
@@ -767,7 +786,8 @@
posBefore = mMediaPlayer.getCurrentPosition();
mMediaPlayer.setDisplay(null);
posAfter = mMediaPlayer.getCurrentPosition();
- assertEquals(posAfter, posBefore, tolerance);
+ // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+ // assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
@@ -776,7 +796,8 @@
mMediaPlayer.setDisplay(getActivity().getSurfaceHolder());
posAfter = mMediaPlayer.getCurrentPosition();
- assertEquals(posAfter, posBefore, tolerance);
+ // TODO: uncomment out line below when MediaPlayer can seek to requested position.
+ // assertEquals(posAfter, posBefore, tolerance);
assertTrue(mMediaPlayer.isPlaying());
Thread.sleep(SLEEP_TIME);
@@ -802,15 +823,34 @@
return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
+ private Camera mCamera;
private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
- final int width = RECORDED_VIDEO_WIDTH;
- final int height = RECORDED_VIDEO_HEIGHT;
+ int width = RECORDED_VIDEO_WIDTH;
+ int height = RECORDED_VIDEO_HEIGHT;
final String file = RECORDED_FILE;
final long durationMs = RECORDED_DURATION_MS;
if (!hasCamera()) {
return;
}
+
+ boolean isSupported = false;
+ mCamera = Camera.open(0);
+ Camera.Parameters parameters = mCamera.getParameters();
+ List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+ for (Camera.Size size : previewSizes)
+ {
+ if (size.width == width && size.height == height) {
+ isSupported = true;
+ break;
+ }
+ }
+ mCamera.release();
+ mCamera = null;
+ if (!isSupported) {
+ width = previewSizes.get(0).width;
+ height = previewSizes.get(0).height;
+ }
checkOrientation(angle);
recordVideo(width, height, angle, file, durationMs);
checkDisplayedVideoSize(width, height, angle, file);
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index f7b6c91..4c90e56 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -60,6 +60,8 @@
private static final int RECORDED_DUR_TOLERANCE_MS = 1000;
private static final int VIDEO_WIDTH = 176;
private static final int VIDEO_HEIGHT = 144;
+ private static int mVideoWidth = VIDEO_WIDTH;
+ private static int mVideoHeight = VIDEO_HEIGHT;
private static final int VIDEO_BIT_RATE_IN_BPS = 128000;
private static final double VIDEO_TIMELAPSE_CAPTURE_RATE_FPS = 1.0;
private static final int AUDIO_BIT_RATE_IN_BPS = 12200;
@@ -219,6 +221,7 @@
int durMs = timelapse? RECORD_TIME_LAPSE_MS: RECORD_TIME_MS;
for (int cameraId = 0; cameraId < nCamera; cameraId++) {
mCamera = Camera.open(cameraId);
+ setSupportedResolution(mCamera);
recordVideoUsingCamera(mCamera, OUTPUT_PATH, durMs, timelapse);
mCamera.release();
mCamera = null;
@@ -226,6 +229,21 @@
}
}
+ private void setSupportedResolution(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+ for (Camera.Size size : previewSizes)
+ {
+ if (size.width == VIDEO_WIDTH && size.height == VIDEO_HEIGHT) {
+ mVideoWidth = VIDEO_WIDTH;
+ mVideoHeight = VIDEO_HEIGHT;
+ return;
+ }
+ }
+ mVideoWidth = previewSizes.get(0).width;
+ mVideoHeight = previewSizes.get(0).height;
+ }
+
private void recordVideoUsingCamera(
Camera camera, String fileName, int durMs, boolean timelapse) throws Exception {
// FIXME:
@@ -242,7 +260,7 @@
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mMediaRecorder.setVideoFrameRate(frameRate);
- mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
mMediaRecorder.setOutputFile(fileName);
mMediaRecorder.setLocation(LATITUDE, LONGITUDE);
@@ -872,6 +890,12 @@
boolean success = false;
Surface surface = null;
int noOfFailure = 0;
+
+ if (!hasH264()) {
+ MediaUtils.skipTest("no codecs");
+ return true;
+ }
+
try {
if (persistent) {
surface = MediaCodec.createPersistentInputSurface();
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 7497da2..ce61d76 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -312,6 +312,11 @@
}
public void testPlayHlsStreamWithTimedId3() throws Throwable {
+ if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+ Log.d(TAG, "Device doesn't have video codec, skipping test");
+ return;
+ }
+
mServer = new CtsTestServer(mContext);
try {
// counter must be final if we want to access it inside onTimedMetaData;
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index e3d2f09..fb1521d 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -174,6 +174,7 @@
private boolean mSignaledDecoderEOS;
protected boolean mCompleted;
+ protected boolean mEncoderIsActive;
protected boolean mEncodeOutputFormatUpdated;
protected final Object mCondition = new Object();
@@ -322,6 +323,10 @@
mCompleted = true;
mCondition.notifyAll(); // condition is always satisfied
}
+ } else {
+ synchronized(mCondition) {
+ mEncoderIsActive = true;
+ }
}
}
}
@@ -395,6 +400,11 @@
break;
}
if (!haveBuffers()) {
+ if (mEncoderIsActive) {
+ mEncoderIsActive = false;
+ Log.d(TAG, "No more input but still getting output from encoder.");
+ continue;
+ }
fail("timed out after " + mBuffersToRender.size()
+ " decoder output and " + mEncInputBuffers.size()
+ " encoder input buffers");
@@ -557,7 +567,6 @@
implements SurfaceTexture.OnFrameAvailableListener {
private static final String TAG = "SurfaceVideoProcessor";
private boolean mFrameAvailable;
- private boolean mEncoderIsActive;
private boolean mGotDecoderEOS;
private boolean mSignaledEncoderEOS;
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 88dbd7c..9a99c22 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,6 +16,9 @@
package android.net.cts;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -23,6 +26,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
@@ -467,4 +471,23 @@
mAvailableLatch.countDown();
}
}
+
+ /** Verify restricted networks cannot be requested. */
+ public void testRestrictedNetworks() {
+ // Verify we can request unrestricted networks:
+ NetworkRequest request = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET).build();
+ NetworkCallback callback = new NetworkCallback();
+ mCm.requestNetwork(request, callback);
+ mCm.unregisterNetworkCallback(callback);
+ // Verify we cannot request restricted networks:
+ request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
+ callback = new NetworkCallback();
+ try {
+ mCm.requestNetwork(request, callback);
+ fail("No exception thrown when restricted network requested.");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+ }
}
diff --git a/tests/tests/os/jni/seccomp_sample_program.cpp b/tests/tests/os/jni/seccomp_sample_program.cpp
index 3c90196..3bc7da4 100644
--- a/tests/tests/os/jni/seccomp_sample_program.cpp
+++ b/tests/tests/os/jni/seccomp_sample_program.cpp
@@ -826,7 +826,7 @@
{0x35, 0, 4, 0x76},
{0x35, 0, 2, 0x79},
{0x35, 0, 241, 0x7a},
- {0x35, 240, 239, 0x7b},
+ {0x35, 240, 239, 0x7c},
{0x35, 238, 239, 0x77},
{0x35, 0, 2, 0x72},
{0x35, 0, 236, 0x73},
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 419f320..af60139 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -29,8 +29,8 @@
private static final String LOG_TAG = "BuildVersionTest";
private static final Set<String> EXPECTED_RELEASES =
- new HashSet<String>(Arrays.asList("5.1", "5.1.1"));
- private static final int EXPECTED_SDK = 22;
+ new HashSet<String>(Arrays.asList("6.0"));
+ private static final int EXPECTED_SDK = 23;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_TAG = "release-keys";
diff --git a/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java b/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
index 0b389a4..d8e128b 100644
--- a/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
+++ b/tests/tests/os/src/android/os/cts/CpuFeaturesTest.java
@@ -82,8 +82,8 @@
}
private static final String[] armv8RequiredFeatures = {
- "wp", "half", "thumb", "fastmult", "vfp", "edsp", "neon",
- "vfpv3", "tlsi", "vfpv4", "idiva", "idivt" };
+ "half", "thumb", "fastmult", "vfp", "edsp", "neon",
+ "vfpv3", "vfpv4", "idiva", "idivt" };
private static void assertInCpuinfo(List<String> features,
String feature) {
diff --git a/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
index 8714100..a95c96e 100644
--- a/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/ConnectivityManagerPermissionTest.java
@@ -53,21 +53,4 @@
// expected
}
}
-
- /**
- * Verify that calling {@link ConnectivityManager#requestRouteToHost(int, int)}
- * requires permissions.
- * <p>Tests Permission:
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
- */
- @SmallTest
- public void testRequestRouteToHost() {
- try {
- mConnectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE, 1);
- fail("Was able to call requestRouteToHost");
- } catch (SecurityException e) {
- // expected
- }
- }
}
-
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index cf6a09d..0962bbd 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -251,7 +251,6 @@
@MediumTest
public void testProcSelfOomAdjSane() {
File f = new File("/proc/self/oom_adj");
- assertTrue(f.canRead());
assertFalse(f.canWrite());
assertFalse(f.canExecute());
}
@@ -259,7 +258,6 @@
@MediumTest
public void testProcSelfOomScoreAdjSane() {
File f = new File("/proc/self/oom_score_adj");
- assertTrue(f.canRead());
assertFalse(f.canWrite());
assertFalse(f.canExecute());
}
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index f7e5443..c260706 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -98,4 +98,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index e75ec94..1378bdb 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -140,6 +140,11 @@
@Override
public void setUp() throws Exception {
+ super.setUp();
+ if (!supportsPrinting()) {
+ return;
+ }
+
// Make sure we start with a clean slate.
clearPrintSpoolerData();
enablePrintServices();
@@ -176,23 +181,26 @@
@Override
public void tearDown() throws Exception {
- // Done with the activity.
- getActivity().finish();
- enableImes();
+ if (supportsPrinting()) {
+ // Done with the activity.
+ getActivity().finish();
+ enableImes();
- // Restore the locale if needed.
- if (mOldLocale != null) {
- Resources resources = getInstrumentation().getTargetContext().getResources();
- DisplayMetrics displayMetrics = resources.getDisplayMetrics();
- Configuration newConfiguration = new Configuration(resources.getConfiguration());
- newConfiguration.locale = mOldLocale;
- mOldLocale = null;
- resources.updateConfiguration(newConfiguration, displayMetrics);
+ // Restore the locale if needed.
+ if (mOldLocale != null) {
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(resources.getConfiguration());
+ newConfiguration.locale = mOldLocale;
+ mOldLocale = null;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ disablePrintServices();
+ // Make sure the spooler is cleaned.
+ clearPrintSpoolerData();
}
-
- disablePrintServices();
- // Make sure the spooler is cleaned.
- clearPrintSpoolerData();
+ super.tearDown();
}
protected void print(final PrintDocumentAdapter adapter) {
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/systemui/Android.mk
similarity index 63%
copy from tests/tests/netlegacy22/Android.mk
copy to tests/tests/systemui/Android.mk
index 3174652..1a15fd2 100644
--- a/tests/tests/netlegacy22/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -12,5 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Build the API tests and the permissions tests using their own makefiles.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSystemUiTestCases
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
new file mode 100644
index 0000000..bf5df5b
--- /dev/null
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.systemui">
+ <uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application>
+ <activity android:name=".LightStatusBarActivity"
+ android:theme="@android:style/Theme.Material.NoActionBar"></activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.systemui">
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
new file mode 100644
index 0000000..626a179
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.systemui;
+
+/**
+ * Copies of non-public {@link android.graphics.Color} APIs
+ */
+public class ColorUtils {
+
+ public static float brightness(int argb) {
+ int r = (argb >> 16) & 0xFF;
+ int g = (argb >> 8) & 0xFF;
+ int b = argb & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+
+ return (V / 255.f);
+ }
+
+ public static float hue(int argb) {
+ int r = (argb >> 16) & 0xFF;
+ int g = (argb >> 8) & 0xFF;
+ int b = argb & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H;
+
+ if (V == temp) {
+ H = 0;
+ } else {
+ final float vtemp = (float) (V - temp);
+ final float cr = (V - r) / vtemp;
+ final float cg = (V - g) / vtemp;
+ final float cb = (V - b) / vtemp;
+
+ if (r == V) {
+ H = cb - cg;
+ } else if (g == V) {
+ H = 2 + cr - cb;
+ } else {
+ H = 4 + cg - cr;
+ }
+
+ H /= 6.f;
+ if (H < 0) {
+ H++;
+ }
+ }
+
+ return H;
+ }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
new file mode 100644
index 0000000..3722320
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.systemui;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+
+/**
+ * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ */
+public class LightStatusBarActivity extends Activity {
+
+ private View mContent;
+
+ public void onCreate(Bundle bundle){
+ super.onCreate(bundle);
+
+ mContent = new View(this);
+ mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT));
+ setContentView(mContent);
+ }
+
+ public void setLightStatusBar(boolean lightStatusBar) {
+ int vis = getWindow().getDecorView().getSystemUiVisibility();
+ if (lightStatusBar) {
+ vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else {
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ getWindow().getDecorView().setSystemUiVisibility(vis);
+ }
+
+ public int getTop() {
+ return mContent.getLocationOnScreen()[1];
+ }
+
+ public int getWidth() {
+ return mContent.getWidth();
+ }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
new file mode 100644
index 0000000..b5bfd51
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
@@ -0,0 +1,235 @@
+/*
+ * 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.systemui;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Test for light status bar.
+ */
+public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
+
+ public static final String TAG = "LightStatusBarTests";
+
+ public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
+
+ public LightStatusBarTests() {
+ super(LightStatusBarActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // As the way to access Instrumentation is changed in the new runner, we need to inject it
+ // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+ // be marked as deprecated and replaced with ActivityTestRule.
+ injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+ }
+
+ public void testLightStatusBarIcons() throws Throwable {
+ PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+ || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ // No status bar on TVs and watches.
+ return;
+ }
+
+ if (!ActivityManager.isHighEndGfx()) {
+ // non-highEndGfx devices don't do colored system bars.
+ return;
+ }
+
+ requestLightStatusBar(Color.RED /* background */);
+ Thread.sleep(1000);
+
+ Bitmap bitmap = takeStatusBarScreenshot();
+ Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
+ boolean success = false;
+
+ try {
+ assertMoreThan("Not enough background pixels", 0.3f,
+ (float) s.backgroundPixels / s.totalPixels(),
+ "Is the status bar background showing correctly (solid red)?");
+
+ assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
+ (float) s.iconPixels / s.foregroundPixels(),
+ "Are the status bar icons colored according to the spec "
+ + "(60% black and 24% black)?");
+
+ assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
+ (float) s.sameHueLightPixels / s.foregroundPixels(),
+ "Are the status bar icons dark?");
+
+ assertLessThan("Too many pixels with a changed hue", 0.05f,
+ (float) s.unexpectedHuePixels / s.foregroundPixels(),
+ "Are the status bar icons color-free?");
+
+ success = true;
+ } finally {
+ if (!success) {
+ Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
+ dumpBitmap(bitmap);
+ }
+ }
+ }
+
+ private void assertMoreThan(String what, float expected, float actual, String hint) {
+ if (!(actual > expected)) {
+ fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+ + "%; " + hint);
+ }
+ }
+
+ private void assertLessThan(String what, float expected, float actual, String hint) {
+ if (!(actual < expected)) {
+ fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+ + "%; " + hint);
+ }
+ }
+
+ private void requestLightStatusBar(final int background) throws Throwable {
+ final LightStatusBarActivity activity = getActivity();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ activity.getWindow().setStatusBarColor(background);
+ activity.setLightStatusBar(true);
+ }
+ });
+ }
+
+ private static class Stats {
+ int backgroundPixels;
+ int iconPixels;
+ int sameHueDarkPixels;
+ int sameHueLightPixels;
+ int unexpectedHuePixels;
+
+ int totalPixels() {
+ return backgroundPixels + iconPixels + sameHueDarkPixels
+ + sameHueLightPixels + unexpectedHuePixels;
+ }
+
+ int foregroundPixels() {
+ return iconPixels + sameHueDarkPixels
+ + sameHueLightPixels + unexpectedHuePixels;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
+ backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
+ unexpectedHuePixels);
+ }
+ }
+
+ private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
+ int iconColor = 0x99000000;
+ int iconPartialColor = 0x3d000000;
+
+ int mixedIconColor = mixSrcOver(background, iconColor);
+ int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+
+ int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
+ bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+ Stats s = new Stats();
+ float eps = 0.005f;
+
+ for (int c : pixels) {
+ if (c == background) {
+ s.backgroundPixels++;
+ continue;
+ }
+
+ // What we expect the icons to be colored according to the spec.
+ if (c == mixedIconColor || c == mixedIconPartialColor) {
+ s.iconPixels++;
+ continue;
+ }
+
+ // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
+ // should still be mostly the same hue.
+ float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
+ if (hueDiff < eps || hueDiff > 1 - eps) {
+ // .. it shouldn't be lighter than the original background though.
+ if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
+ s.sameHueLightPixels++;
+ } else {
+ s.sameHueDarkPixels++;
+ }
+ continue;
+ }
+
+ s.unexpectedHuePixels++;
+ }
+
+ return s;
+ }
+
+ private void dumpBitmap(Bitmap bitmap) {
+ FileOutputStream fileStream = null;
+ try {
+ fileStream = new FileOutputStream(DUMP_PATH);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+ fileStream.flush();
+ } catch (Exception e) {
+ Log.e(TAG, "Dumping bitmap failed.", e);
+ } finally {
+ if (fileStream != null) {
+ try {
+ fileStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private int mixSrcOver(int background, int foreground) {
+ int bgAlpha = Color.alpha(background);
+ int bgRed = Color.red(background);
+ int bgGreen = Color.green(background);
+ int bgBlue = Color.blue(background);
+
+ int fgAlpha = Color.alpha(foreground);
+ int fgRed = Color.red(foreground);
+ int fgGreen = Color.green(foreground);
+ int fgBlue = Color.blue(foreground);
+
+ return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
+ fgRed + (255 - fgAlpha) * bgRed / 255,
+ fgGreen + (255 - fgAlpha) * bgGreen / 255,
+ fgBlue + (255 - fgAlpha) * bgBlue / 255);
+ }
+
+ private Bitmap takeStatusBarScreenshot() {
+ Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+ return Bitmap.createBitmap(fullBitmap, 0, 0,
+ getActivity().getWidth(), getActivity().getTop());
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java b/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
index 00a56ac..3a0dbd3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseRemoteTelecomTest.java
@@ -52,17 +52,20 @@
@Override
protected void tearDown() throws Exception {
if (mShouldTestTelecom) {
- tearDownConnectionServices(TEST_PHONE_ACCOUNT_HANDLE, TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
+ tearDownRemoteConnectionService(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
}
super.tearDown();
}
protected void setupConnectionServices(MockConnectionService connectionService,
- MockConnectionService remoteConnectionService, int flags)
- throws Exception {
+ MockConnectionService remoteConnectionService, int flags) throws Exception {
// Setup the primary connection service first
setupConnectionService(connectionService, flags);
+ setupRemoteConnectionService(remoteConnectionService, flags);
+ }
+ protected void setupRemoteConnectionService(MockConnectionService remoteConnectionService,
+ int flags) throws Exception {
if (remoteConnectionService != null) {
this.remoteConnectionService = remoteConnectionService;
} else {
@@ -78,19 +81,23 @@
TEST_REMOTE_PHONE_ACCOUNT_HANDLE,
REMOTE_ACCOUNT_LABEL,
TEST_REMOTE_PHONE_ACCOUNT_ADDRESS);
+ // Wait till the adb commands have executed and account is in Telecom database.
+ assertPhoneAccountRegistered(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
}
if ((flags & FLAG_ENABLE) != 0) {
TestUtils.enablePhoneAccount(getInstrumentation(), TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
+ // Wait till the adb commands have executed and account is enabled in Telecom database.
+ assertPhoneAccountEnabled(TEST_REMOTE_PHONE_ACCOUNT_HANDLE);
}
}
- protected void tearDownConnectionServices(PhoneAccountHandle accountHandle,
- PhoneAccountHandle remoteAccountHandle) throws Exception {
- // Teardown the primary connection service first
- tearDownConnectionService(accountHandle);
-
+ protected void tearDownRemoteConnectionService(PhoneAccountHandle remoteAccountHandle)
+ throws Exception {
+ assertNumConnections(this.remoteConnectionService, 0);
mTelecomManager.unregisterPhoneAccount(remoteAccountHandle);
CtsRemoteConnectionService.tearDown();
+ //Telecom doesn't unbind the remote connection service at the end of all calls today.
+ //assertCtsRemoteConnectionServiceUnbound();
this.remoteConnectionService = null;
}
@@ -210,4 +217,22 @@
"Remote Conference should be in state " + state
);
}
+
+ void assertCtsRemoteConnectionServiceUnbound() {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected(){
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ return CtsRemoteConnectionService.isServiceUnbound();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "CtsRemoteConnectionService not yet unbound!"
+ );
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 31ca09b..d7fe239 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -110,13 +110,13 @@
TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
}
tearDownConnectionService(TEST_PHONE_ACCOUNT_HANDLE);
+ assertMockInCallServiceUnbound();
}
super.tearDown();
}
protected PhoneAccount setupConnectionService(MockConnectionService connectionService,
- int flags)
- throws Exception {
+ int flags) throws Exception {
if (connectionService != null) {
this.connectionService = connectionService;
} else {
@@ -130,14 +130,18 @@
}
if ((flags & FLAG_ENABLE) != 0) {
TestUtils.enablePhoneAccount(getInstrumentation(), TEST_PHONE_ACCOUNT_HANDLE);
+ // Wait till the adb commands have executed and account is enabled in Telecom database.
+ assertPhoneAccountEnabled(TEST_PHONE_ACCOUNT_HANDLE);
}
return TEST_PHONE_ACCOUNT;
}
protected void tearDownConnectionService(PhoneAccountHandle accountHandle) throws Exception {
+ assertNumConnections(this.connectionService, 0);
mTelecomManager.unregisterPhoneAccount(accountHandle);
CtsConnectionService.tearDown();
+ assertCtsConnectionServiceUnbound();
this.connectionService = null;
}
@@ -513,6 +517,22 @@
}
+ void assertNumConnections(final MockConnectionService connService, final int numConnections) {
+ waitUntilConditionIsTrueOrTimeout(new Condition() {
+ @Override
+ public Object expected() {
+ return numConnections;
+ }
+ @Override
+ public Object actual() {
+ return connService.getAllConnections().size();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "ConnectionService should contain " + numConnections + " connections."
+ );
+ }
+
void assertMuteState(final InCallService incallService, final boolean isMuted) {
waitUntilConditionIsTrueOrTimeout(
new Condition() {
@@ -621,7 +641,7 @@
}
},
WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
- "Call should be in state " + state
+ "Call: " + call + " should be in state " + state
);
}
@@ -731,6 +751,79 @@
);
}
+ void assertPhoneAccountRegistered(final PhoneAccountHandle handle) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ return mTelecomManager.getPhoneAccount(handle) != null;
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Phone account registration failed for " + handle
+ );
+ }
+
+ void assertPhoneAccountEnabled(final PhoneAccountHandle handle) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle);
+ return (phoneAccount != null && phoneAccount.isEnabled());
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Phone account enable failed for " + handle
+ );
+ }
+
+ void assertCtsConnectionServiceUnbound() {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ return CtsConnectionService.isServiceUnbound();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "CtsConnectionService not yet unbound!"
+ );
+ }
+
+ void assertMockInCallServiceUnbound() {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ return MockInCallService.isServiceUnbound();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "MockInCallService not yet unbound!"
+ );
+ }
+
void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
String description) {
final long start = System.currentTimeMillis();
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index 121d559..508870c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -50,7 +50,6 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mContext = getInstrumentation().getContext();
if (mShouldTestTelecom) {
addOutgoingCalls();
addConferenceCall(mCall1, mCall2);
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index afaa3eb..836ca48 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -48,20 +48,13 @@
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
+ // Add second connection (add existing connection)
final MockConnection connection = new MockConnection();
connection.setOnHold();
CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
-
- try {
- if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
- fail("No call added to InCallService.");
- }
- } catch (InterruptedException e) {
- Log.i(TAG, "Test interrupted!");
- }
-
- final MockInCallService inCallService = mInCallCallbacks.getService();
- final Call call = inCallService.getLastCall();
+ assertNumCalls(mInCallCallbacks.getService(), 2);
+ mInCallCallbacks.lock.drainPermits();
+ final Call call = mInCallCallbacks.getService().getLastCall();
assertCallState(call, Call.STATE_HOLDING);
}
@@ -77,17 +70,22 @@
Collection<Connection> connections = CtsConnectionService.getAllConnectionsFromTelecom();
assertEquals(1, connections.size());
assertTrue(connections.contains(connection1));
+ // Need to move this to active since we reject the 3rd incoming call below if this is in
+ // dialing state (b/23428950).
+ connection1.setActive();
+ assertCallState(mInCallCallbacks.getService().getLastCall(), Call.STATE_ACTIVE);
// Add second connection (add existing connection)
final Connection connection2 = new MockConnection();
CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection2);
-
+ assertNumCalls(mInCallCallbacks.getService(), 2);
+ mInCallCallbacks.lock.drainPermits();
connections = CtsConnectionService.getAllConnectionsFromTelecom();
assertEquals(2, connections.size());
assertTrue(connections.contains(connection2));
// Add third connection (incoming call)
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final Connection connection3 = verifyConnectionForIncomingCall();
connections = CtsConnectionService.getAllConnectionsFromTelecom();
assertEquals(3, connections.size());
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index 3c30e6b..d8d5773 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -16,6 +16,9 @@
package android.telecom.cts;
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
@@ -23,6 +26,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.RemoteConference;
import android.telecom.RemoteConnection;
+import android.util.Log;
import java.util.Collection;
@@ -43,10 +47,12 @@
*
*/
public class CtsConnectionService extends ConnectionService {
+ private static String LOG_TAG = "CtsConnectionService";
// This is the connection service implemented by the test
private static ConnectionService sConnectionService;
// This is the connection service registered with Telecom
private static ConnectionService sTelecomConnectionService;
+ private static boolean mIsServiceUnbound;
public CtsConnectionService() throws Exception {
super();
@@ -65,13 +71,14 @@
private static Object sLock = new Object();
public static void setUp(PhoneAccountHandle phoneAccountHandle,
- ConnectionService connectionService)
- throws Exception {
+ ConnectionService connectionService) throws Exception {
synchronized(sLock) {
if (sConnectionService != null) {
throw new Exception("Mock ConnectionService exists. Failed to call tearDown().");
}
sConnectionService = connectionService;
+ // Cant override the onBind method for ConnectionService, so reset it here.
+ mIsServiceUnbound = false;
}
}
@@ -178,4 +185,16 @@
}
}
}
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(LOG_TAG, "Service unbounded");
+ assertFalse(mIsServiceUnbound);
+ mIsServiceUnbound = true;
+ return super.onUnbind(intent);
+ }
+
+ public static boolean isServiceUnbound() {
+ return mIsServiceUnbound;
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
index 3738487..13b525f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRemoteConnectionService.java
@@ -16,11 +16,15 @@
package android.telecom.cts;
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.ConnectionService;
import android.telecom.PhoneAccountHandle;
+import android.util.Log;
/**
* This is the Remote ConnectionService for Telecom's CTS App. Since telecom requires that a
@@ -39,10 +43,12 @@
*
*/
public class CtsRemoteConnectionService extends ConnectionService {
+ private static String LOG_TAG = "CtsConnectionService";
// This is the connection service implemented by the test
private static ConnectionService sConnectionService;
// This is the connection service registered with Telecom
private static ConnectionService sTelecomConnectionService;
+ private static boolean mIsServiceUnbound;
public CtsRemoteConnectionService() throws Exception {
super();
@@ -64,13 +70,14 @@
private static Object sLock = new Object();
public static void setUp(PhoneAccountHandle phoneAccountHandle,
- ConnectionService connectionService)
- throws Exception {
+ ConnectionService connectionService) throws Exception {
synchronized(sLock) {
if (sConnectionService != null) {
throw new Exception("Mock ConnectionService exists. Failed to call tearDown().");
}
sConnectionService = connectionService;
+ // Cant override the onBind method for ConnectionService, so reset it here.
+ mIsServiceUnbound = false;
}
}
@@ -124,4 +131,16 @@
sTelecomConnectionService.addConference(conference);
}
}
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(LOG_TAG, "Service unbounded");
+ assertFalse(mIsServiceUnbound);
+ mIsServiceUnbound = true;
+ return super.onUnbind(intent);
+ }
+
+ public static boolean isServiceUnbound() {
+ return mIsServiceUnbound;
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 19d27af..02d2f15 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -188,7 +188,7 @@
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final MockConnection connection = verifyConnectionForIncomingCall();
final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -209,7 +209,7 @@
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final MockConnection connection = verifyConnectionForIncomingCall();
final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -232,7 +232,7 @@
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final MockConnection connection = verifyConnectionForIncomingCall();
final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -390,7 +390,7 @@
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
verifyConnectionForIncomingCall();
final MockInCallService inCallService = mInCallCallbacks.getService();
@@ -428,7 +428,7 @@
assertEquals("InCallService.getCalls() should return list with 1 call.", 1, calls.size());
assertEquals(call1, calls.get(0));
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
verifyConnectionForIncomingCall();
final Call call2 = inCallService.getLastCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index d556baa..9bb83a1 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -66,6 +66,7 @@
if (mRemoteConnection != null) {
mRemoteConnection.reject();
}
+ destroy();
}
@Override
@@ -90,18 +91,20 @@
public void onDisconnect() {
super.onDisconnect();
setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
- destroy();
if (mRemoteConnection != null) {
mRemoteConnection.disconnect();
}
+ destroy();
}
@Override
public void onAbort() {
super.onAbort();
+ setDisconnected(new DisconnectCause(DisconnectCause.UNKNOWN));
if (mRemoteConnection != null) {
mRemoteConnection.abort();
}
+ destroy();
}
@Override
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index 1856603..0f1f538 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -16,10 +16,14 @@
package android.telecom.cts;
+import static org.junit.Assert.assertFalse;
+
+import android.content.Intent;
import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.InCallService;
import android.util.ArrayMap;
+import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -27,6 +31,7 @@
import java.util.concurrent.Semaphore;
public class MockInCallService extends InCallService {
+ private static String LOG_TAG = "MockInCallService";
private ArrayList<Call> mCalls = new ArrayList<>();
private ArrayList<Call> mConferenceCalls = new ArrayList<>();
private static InCallServiceCallbacks sCallbacks;
@@ -34,6 +39,7 @@
new ArrayMap<Call, MockVideoCallCallback>();
private static final Object sLock = new Object();
+ private static boolean mIsServiceUnbound;
public static abstract class InCallServiceCallbacks {
private MockInCallService mService;
@@ -152,9 +158,11 @@
@Override
public android.os.IBinder onBind(android.content.Intent intent) {
+ Log.i(LOG_TAG, "Service bounded");
if (getCallbacks() != null) {
getCallbacks().setService(this);
}
+ mIsServiceUnbound = false;
return super.onBind(intent);
}
@@ -312,4 +320,16 @@
public MockVideoCallCallback getVideoCallCallback(Call call) {
return mVideoCallCallbacks.get(call);
}
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(LOG_TAG, "Service unbounded");
+ assertFalse(mIsServiceUnbound);
+ mIsServiceUnbound = true;
+ return super.onUnbind(intent);
+ }
+
+ public static boolean isServiceUnbound() {
+ return mIsServiceUnbound;
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
index 8ffcf48..e95a290 100644
--- a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
@@ -62,7 +62,5 @@
res.wait(CS_WAIT_MILLIS);
}
assertEquals(address, res[0]);
-
- tearDownConnectionService(account.getAccountHandle());
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
index f2422c9..bba9a44 100644
--- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
@@ -18,6 +18,8 @@
import static android.telecom.cts.TestUtils.shouldTestTelecom;
+import android.content.Context;
+import android.media.AudioManager;
import android.os.Bundle;
import android.telecom.CallAudioState;
import android.telecom.TelecomManager;
@@ -35,15 +37,13 @@
}
}
- // TODO: Need to send some commands to the UserManager via adb to do setup
+ /* TODO: Need to send some commands to the UserManager via adb to do setup
public void testDisallowOutgoingCallsForSecondaryUser() {
+ } */
- }
-
- // TODO: Need to figure out a way to mock emergency calls without adb root
+ /* TODO: Need to figure out a way to mock emergency calls without adb root
public void testOutgoingCallBroadcast_isSentForAllCalls() {
-
- }
+ } */
/**
* Verifies that providing the EXTRA_START_CALL_WITH_SPEAKERPHONE extra starts the call with
@@ -68,11 +68,15 @@
return;
}
+ AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ int expectedRoute = am.isWiredHeadsetOn() ?
+ CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
+
final Bundle extras = new Bundle();
extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
placeAndVerifyCall(extras);
verifyConnectionForOutgoingCall();
- assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
+ assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
}
public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
@@ -80,8 +84,12 @@
return;
}
+ AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ int expectedRoute = am.isWiredHeadsetOn() ?
+ CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
+
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
- assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
+ assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index 3fc65ea..787966a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -61,7 +61,6 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mContext = getInstrumentation().getContext();
if (mShouldTestTelecom) {
addRemoteConferenceCall();
verifyRemoteConferenceObject(mRemoteConferenceObject, mRemoteConference, mConference);
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index 79fb592..5b552a0 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -1210,7 +1210,6 @@
};
mRemoteConnectionObject.registerCallback(callback, handler);
mRemoteConnection.createMockVideoProvider();
- mRemoteConnection.setVideoProvider(mRemoteConnection.getMockVideoProvider());
callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
mRemoteConnectionObject.unregisterCallback(callback);
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index 466a90b..e7130ba 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -35,21 +35,12 @@
}
}
- @Override
- protected void tearDown() throws Exception {
- if (mInCallCallbacks != null && mInCallCallbacks.getService() != null) {
- mInCallCallbacks.getService().disconnectLastCall();
- assertNumCalls(mInCallCallbacks.getService(), 0);
- }
- super.tearDown();
- }
-
public void testIncomingCallShortPress_acceptsCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final MockConnection connection = verifyConnectionForIncomingCall();
final Call call = mInCallCallbacks.getService().getLastCall();
@@ -66,7 +57,7 @@
return;
}
- addAndVerifyNewIncomingCall(getTestNumber(), null);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
final MockConnection connection = verifyConnectionForIncomingCall();
final Call call = mInCallCallbacks.getService().getLastCall();
@@ -119,16 +110,6 @@
assertConnectionState(connection, Connection.STATE_DISCONNECTED);
}
- public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
- if (!mShouldTestTelecom) {
- return;
- }
-
- placeAndVerifyCall();
- verifyConnectionForOutgoingCall();
- assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
- }
-
private void sendMediaButtonShortPress() throws Exception {
sendMediaButtonPress(false /* longPress */);
}
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
index 176c50c..e15b45f 100644
--- a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.SystemClock;
import android.telephony.SmsManager;
@@ -84,6 +85,7 @@
private Random mRandom;
private SentReceiver mSentReceiver;
private TelephonyManager mTelephonyManager;
+ private PackageManager mPackageManager;
private static class SentReceiver extends BroadcastReceiver {
private final Object mLock;
@@ -164,15 +166,26 @@
mRandom = new Random();
mTelephonyManager =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mPackageManager = mContext.getPackageManager();
}
public void testSendMmsMessage() {
- if (!mTelephonyManager.isSmsCapable()) {
- Log.i(TAG, "testSendMmsMessage skipped: not SMS capable");
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ Log.i(TAG, "testSendMmsMessage skipped: no telephony available");
return;
}
Log.i(TAG, "testSendMmsMessage");
+ // Prime the MmsService so that MMS config is loaded
+ final SmsManager smsManager = SmsManager.getDefault();
+ smsManager.getAutoPersisting();
+ // MMS config is loaded asynchronously. Wait a bit so it will be loaded.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+
final Context context = getContext();
// Register sent receiver
mSentReceiver = new SentReceiver();
@@ -193,7 +206,7 @@
// Send
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, new Intent(ACTION_MMS_SENT), 0);
- SmsManager.getDefault().sendMultimediaMessage(context,
+ smsManager.sendMultimediaMessage(context,
contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
sendFile.delete();
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 41fe996..8b94d00 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -225,7 +225,10 @@
break;
case TelephonyManager.PHONE_TYPE_NONE:
- if (mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) != null) {
+ boolean nwSupported = mCm.isNetworkSupported(mCm.TYPE_WIFI);
+ PackageManager packageManager = getContext().getPackageManager();
+ // only check serial number & MAC address if device report wifi feature
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
assertSerialNumber();
assertMacAddress(getWifiMacAddress());
} else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) {
diff --git a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
index 6eb09eb..9ab815f 100644
--- a/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
+++ b/tests/tests/text/src/android/text/format/cts/DateUtilsTest.java
@@ -94,20 +94,20 @@
final long ONE_SECOND_IN_MS = 1000;
assertEquals("0 minutes ago",
DateUtils.getRelativeTimeSpanString(mBaseTime - ONE_SECOND_IN_MS));
- assertEquals("in 0 minutes",
+ assertEquals("In 0 minutes",
DateUtils.getRelativeTimeSpanString(mBaseTime + ONE_SECOND_IN_MS));
final long ONE_MINUTE_IN_MS = 60 * ONE_SECOND_IN_MS;
assertEquals("1 minute ago", DateUtils.getRelativeTimeSpanString(0, ONE_MINUTE_IN_MS,
DateUtils.MINUTE_IN_MILLIS));
- assertEquals("in 1 minute", DateUtils.getRelativeTimeSpanString(ONE_MINUTE_IN_MS, 0,
+ assertEquals("In 1 minute", DateUtils.getRelativeTimeSpanString(ONE_MINUTE_IN_MS, 0,
DateUtils.MINUTE_IN_MILLIS));
final long ONE_HOUR_IN_MS = 60 * 60 * 1000;
final long TWO_HOURS_IN_MS = 2 * ONE_HOUR_IN_MS;
assertEquals("2 hours ago", DateUtils.getRelativeTimeSpanString(mBaseTime - TWO_HOURS_IN_MS,
mBaseTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_NUMERIC_DATE));
- assertEquals("in 2 hours", DateUtils.getRelativeTimeSpanString(mBaseTime + TWO_HOURS_IN_MS,
+ assertEquals("In 2 hours", DateUtils.getRelativeTimeSpanString(mBaseTime + TWO_HOURS_IN_MS,
mBaseTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_NUMERIC_DATE));
}
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 10d08d0..482edb0 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -255,7 +255,7 @@
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
- // |first line
+ // first lin|e
// second line
// last line
assertSelection(0);
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 3c6028f..6514402 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -165,6 +165,9 @@
// Wait for things to settle.
getUiDevice().waitForIdle();
+ // Wait for Activity draw finish
+ getInstrumentation().waitForIdleSync();
+
// Clear the window animation stats to be with a clean slate.
uiAutomation.clearWindowAnimationFrameStats();
@@ -177,6 +180,9 @@
// Wait for things to settle.
getUiDevice().waitForIdle();
+ // Wait for Activity draw finish
+ getInstrumentation().waitForIdleSync();
+
// Get the frame stats.
WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats();
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
index cb62694..c97e020 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
@@ -28,13 +28,19 @@
*/
public class SamplePointVerifier extends BitmapVerifier {
private static final String TAG = "SamplePoint";
- private Point[] mTestPoints;
- private int[] mExpectedColors;
- private int mTolerance = 20;
+ private static final int DEFAULT_TOLERANCE = 20;
+ private final Point[] mTestPoints;
+ private final int[] mExpectedColors;
+ private final int mTolerance;
public SamplePointVerifier(Point[] testPoints, int[] expectedColors) {
+ this(testPoints, expectedColors, DEFAULT_TOLERANCE);
+ }
+
+ public SamplePointVerifier(Point[] testPoints, int[] expectedColors, int tolerance) {
mTestPoints = testPoints;
mExpectedColors = expectedColors;
+ mTolerance = tolerance;
}
@Override
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 2726dac..38777a2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -16,6 +16,7 @@
package android.uirendering.cts.testclasses;
+import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -163,6 +164,9 @@
@SmallTest
public void testWebViewClipWithCircle() {
+ if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+ return; // no WebView to run test on
+ }
createTest()
// golden client - draw a simple non-AA circle
.addCanvasClient(new CanvasClient() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index 2061023..4582935 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -32,6 +32,7 @@
if (getActivity().getOnTv()) {
shadowColorValue = 0xBB;
}
+ // Use a higher threshold (30) than default value (20);
SamplePointVerifier verifier = new SamplePointVerifier(
new Point[] {
// view area
@@ -46,7 +47,8 @@
Color.WHITE,
Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
- });
+ },
+ 30);
createTest()
.addLayout(R.layout.simple_shadow_layout, null, true/* HW only */)
.runWithVerifier(verifier);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index d585f5f..57c67bd 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -48,7 +48,7 @@
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
mHandler = new RenderSpecHandler();
int uiMode = getResources().getConfiguration().uiMode;
- mOnTv = (uiMode & Configuration.UI_MODE_TYPE_TELEVISION) == Configuration.UI_MODE_TYPE_TELEVISION;
+ mOnTv = (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
}
public boolean getOnTv() {
diff --git a/tests/tests/view/src/android/view/cts/MotionEventTest.java b/tests/tests/view/src/android/view/cts/MotionEventTest.java
index cdedca4..10ea33a 100644
--- a/tests/tests/view/src/android/view/cts/MotionEventTest.java
+++ b/tests/tests/view/src/android/view/cts/MotionEventTest.java
@@ -180,6 +180,40 @@
assertEquals(mMotionEvent2.getDeviceId(), motionEvent.getDeviceId());
}
+ public void testReadFromParcelWithInvalidPointerCountSize() {
+ Parcel parcel = Parcel.obtain();
+ mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+ // Move to pointer id count.
+ parcel.setDataPosition(4);
+ parcel.writeInt(17);
+
+ parcel.setDataPosition(0);
+ try {
+ MotionEvent.CREATOR.createFromParcel(parcel);
+ fail("deserialized invalid parcel");
+ } catch (RuntimeException e) {
+ // Expected.
+ }
+ }
+
+ public void testReadFromParcelWithInvalidSampleSize() {
+ Parcel parcel = Parcel.obtain();
+ mMotionEvent2.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+ // Move to sample count.
+ parcel.setDataPosition(2 * 4);
+ parcel.writeInt(0x000f0000);
+
+ parcel.setDataPosition(0);
+ try {
+ MotionEvent.CREATOR.createFromParcel(parcel);
+ fail("deserialized invalid parcel");
+ } catch (RuntimeException e) {
+ // Expected.
+ }
+ }
+
public void testToString() {
// make sure this method never throw exception.
mMotionEvent2.toString();
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index 374c216..fa1ab70 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -19,7 +19,5 @@
<option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionApp.apk" />
<option name="run-command:run-command"
value="settings put secure voice_interaction_service android.voiceinteraction.service/.MainInteractionService" />
- <option name="run-command:teardown-command"
- value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
<option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionTestCases.apk" />
</configuration>
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
index 0fa89e1..6b47eb4 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionTest.java
@@ -59,7 +59,16 @@
@Override
protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
+ if (mReceiver != null) {
+ try {
+ mContext.unregisterReceiver(mReceiver);
+ } catch (IllegalArgumentException e) {
+ // This exception is thrown if mReceiver in
+ // the above call to unregisterReceiver is never registered.
+ // If so, no harm done by ignoring this exception.
+ }
+ mReceiver = null;
+ }
super.tearDown();
}
diff --git a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
index 1c9ee71..15069ec 100644
--- a/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/testapp/AndroidManifest.xml
@@ -23,7 +23,7 @@
<activity android:name="TestApp"
android:label="Voice Interaction Test App"
- android:theme="@android:style/Theme.Material.Light">
+ android:theme="@android:style/Theme.DeviceDefault">
<intent-filter>
<action android:name="android.intent.action.TEST_APP" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 0a3974d..e3be691 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -17,7 +17,5 @@
<option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsService.apk" />
<option name="run-command:run-command"
value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
- <option name="run-command:teardown-command"
- value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
<option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsTestCases.apk" />
</configuration>
diff --git a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
index c2b7e18..aff1160 100644
--- a/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
+++ b/tests/tests/voicesettings/service/src/android/voicesettings/service/MainInteractionSession.java
@@ -24,6 +24,7 @@
import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
import static android.provider.Settings.EXTRA_BATTERY_SAVER_MODE_ENABLED;
+import android.app.VoiceInteractor;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
@@ -138,9 +139,10 @@
@Override
public void onRequestCompleteVoice(CompleteVoiceRequest request) {
- CharSequence prompt = request.getVoicePrompt().getVoicePromptAt(0);
+ VoiceInteractor.Prompt prompt = request.getVoicePrompt();
+ CharSequence message = (prompt != null ? prompt.getVoicePromptAt(0) : "(none)");
Log.i(TAG, "in Session testcasetype = " + mTestType +
- ", onRequestCompleteVoice recvd. message = " + prompt);
+ ", onRequestCompleteVoice recvd. message = " + message);
AsyncTaskArg asyncTaskArg = new AsyncTaskArg().setRequest(request).setCompleteReq(true);
newTask().execute(asyncTaskArg);
}
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index 8abe396..9ce743e 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -16,6 +16,8 @@
package android.voicesettings.cts;
+import static android.provider.Settings.ACTION_VOICE_CONTROL_AIRPLANE_MODE;
+
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.Log;
@@ -33,9 +35,20 @@
}
public void testAll() throws Exception {
+ if (!isIntentSupported(ACTION_VOICE_CONTROL_AIRPLANE_MODE)) {
+ Log.e(TAG, "Voice intent for Airplane Mode NOT supported. existing the test");
+ return;
+ }
+ int mode;
+ try {
+ mode = getMode();
+ Log.i(TAG, "Before testing, AIRPLANE_MODE is set to: " + mode);
+ } catch (Settings.SettingNotFoundException e) {
+ // if the mode is not supported, don't run the test.
+ Log.i(TAG, "airplane mode is not found in Settings. Skipping AirplaneModeTest");
+ return;
+ }
startTestActivity("AIRPLANE_MODE");
- int mode = getMode();
- Log.i(TAG, "Before testing, AIRPLANE_MODE is set to: " + mode);
if (mode == AIRPLANE_MODE_IS_OFF) {
// mode is currently OFF.
// run a test to turn it on.
@@ -70,7 +83,7 @@
return true;
}
- private int getMode() throws Exception {
+ private int getMode() throws Settings.SettingNotFoundException {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON);
}
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
index 3d1357a..983e27b 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
@@ -16,6 +16,8 @@
package android.voicesettings.cts;
+import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
+
import android.content.Context;
import android.os.PowerManager;
import android.util.Log;
@@ -30,6 +32,10 @@
}
public void testAll() throws Exception {
+ if (!isIntentSupported(ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE)) {
+ Log.e(TAG, "Voice intent for Battery Saver Mode NOT supported. existing the test");
+ return;
+ }
startTestActivity("BATTERYSAVER_MODE");
boolean modeIsOn = isModeOn();
Log.i(TAG, "Before testing, BATTERYSAVER_MODE is set to: " + modeIsOn);
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
index 5386497..529c160 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
@@ -53,10 +54,30 @@
@Override
protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mActivityDoneReceiver);
+ if (mActivityDoneReceiver != null) {
+ try {
+ mContext.unregisterReceiver(mActivityDoneReceiver);
+ } catch (IllegalArgumentException e) {
+ // This exception is thrown if mActivityDoneReceiver in
+ // the above call to unregisterReceiver is never registered.
+ // If so, no harm done by ignoring this exception.
+ }
+ mActivityDoneReceiver = null;
+ }
super.tearDown();
}
+ protected boolean isIntentSupported(String intentStr) {
+ Intent intent = new Intent(intentStr);
+ final PackageManager manager = mContext.getPackageManager();
+ assertNotNull(manager);
+ if (manager.resolveActivity(intent, 0) == null) {
+ Log.i(TAG, "No Voice Activity found for the intent: " + intentStr);
+ return false;
+ }
+ return true;
+ }
+
protected void startTestActivity(String intentSuffix) {
Intent intent = new Intent();
intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
@@ -69,9 +90,6 @@
protected void registerBroadcastReceiver(Utils.TestcaseType testCaseType) throws Exception {
mTestCaseType = testCaseType;
mLatch = new CountDownLatch(1);
- if (mActivityDoneReceiver != null) {
- mContext.unregisterReceiver(mActivityDoneReceiver);
- }
mActivityDoneReceiver = new ActivityDoneReceiver();
mContext.registerReceiver(mActivityDoneReceiver,
new IntentFilter(Utils.BROADCAST_INTENT + testCaseType.toString()));
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
index 8c2efbe..420da8f 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
@@ -16,6 +16,7 @@
package android.voicesettings.cts;
+import static android.provider.Settings.ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE;
import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED;
import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES;
@@ -39,9 +40,20 @@
}
public void testAll() throws Exception {
+ if (!isIntentSupported(ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE)) {
+ Log.e(TAG, "Voice intent for Zen Mode NOT supported. existing the test");
+ return;
+ }
+ int mode;
+ try {
+ mode = getMode();
+ Log.i(TAG, "Before testing, zen-mode is set to: " + mode);
+ } catch (Settings.SettingNotFoundException e) {
+ // if the mode is not supported, don't run the test.
+ Log.i(TAG, "zen_mode is not found in Settings. Skipping ZenModeTest");
+ return;
+ }
startTestActivity("ZEN_MODE");
- int mode = getMode();
- Log.i(TAG, "Before testing, zen-mode is set to: " + mode);
if (mode == ZEN_MODE_IS_OFF) {
// mode is currently OFF.
// run a test to turn it on.
@@ -85,7 +97,7 @@
return true;
}
- private int getMode() throws Exception {
+ private int getMode() throws Settings.SettingNotFoundException {
return Settings.Global.getInt(mContext.getContentResolver(), ZEN_MODE);
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 3130a26..01938c2 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -24,6 +24,7 @@
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources.NotFoundException;
import android.cts.util.PollingCheck;
@@ -4416,9 +4417,18 @@
public void testSetGetBreakStrategy() {
TextView tv = new TextView(mActivity);
+ final PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+
// The default value is from the theme, here the default is BREAK_STRATEGY_HIGH_QUALITY for
- // TextView.
- assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
+ // TextView except for Android Wear. The default value for Android Wear is
+ // BREAK_STRATEGY_BALANCED.
+ if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ // Android Wear
+ assertEquals(Layout.BREAK_STRATEGY_BALANCED, tv.getBreakStrategy());
+ } else {
+ // All other form factor.
+ assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
+ }
tv.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
assertEquals(Layout.BREAK_STRATEGY_SIMPLE, tv.getBreakStrategy());
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index fa930df..782e6ab 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
@Option(name="cts-install-path", description="the path to the cts installation to use")
private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
- public static final String CTS_BUILD_VERSION = "6.0_r0";
+ public static final String CTS_BUILD_VERSION = "6.0_r1";
public static final String CTS_PACKAGE = "com.android.cts.tradefed.testtype";
/**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
index b5f0dfc..61561a5 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
@@ -17,6 +17,7 @@
import com.android.cts.util.AbiUtils;
import com.android.cts.tradefed.result.CtsXmlResultReporter;
+import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IFolderBuildInfo;
@@ -49,7 +50,6 @@
private static final String EXTENDED_INSTRUMENTATION_NAME =
"com.android.compatibility.common.deviceinfo.DeviceInfoInstrument";
private static final String DEVICE_INFO_FILES = "device-info-files";
- private static final String DEVICE_RESULT_DIR = "/sdcard/" + DEVICE_INFO_FILES;
public static final Set<String> IDS = new HashSet<String>();
public static final Set<String> EXTENDED_IDS = new HashSet<String>();
@@ -87,7 +87,8 @@
ITestInvocationListener listener, IBuildInfo buildInfo)
throws DeviceNotAvailableException {
// Clear files in device test result directory
- device.executeShellCommand(String.format("rm -rf %s", DEVICE_RESULT_DIR));
+ String deviceResultDir = getDeviceResultDir(device);
+ device.executeShellCommand(String.format("rm -rf %s", deviceResultDir));
runInstrumentation(device, abi, testApkDir, listener, EXTENDED_APK_NAME,
EXTENDED_APP_PACKAGE_NAME, EXTENDED_INSTRUMENTATION_NAME);
// Copy files in remote result directory to local directory
@@ -131,9 +132,12 @@
localResultDir = new File(localResultDir, DEVICE_INFO_FILES);
localResultDir.mkdirs();
+
+ String deviceResultDir = getDeviceResultDir(device);
+
// Pull files from device result directory to local result directory
String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(),
- DEVICE_RESULT_DIR, localResultDir.getAbsolutePath());
+ deviceResultDir, localResultDir.getAbsolutePath());
if (!execute(command)) {
Log.e(LOG_TAG, String.format("Failed to run %s", command));
}
@@ -148,4 +152,14 @@
return false;
}
}
+
+ private static String getDeviceResultDir(ITestDevice device) {
+ String externalStorePath = device.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
+ if (externalStorePath == null) {
+ Log.e(LOG_TAG, String.format(
+ "Failed to get external storage path on device %s", device.getSerialNumber()));
+ return null;
+ }
+ return String.format("%s/%s", externalStorePath, DEVICE_INFO_FILES);
+ }
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
index f5a3d02..45224f6 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestPackageResult.java
@@ -254,12 +254,12 @@
if (perfResult == null) {
perfResult = CtsHostStore.removeCtsResult(mDeviceSerial, mAbi, test.toString());
}
- if (perfResult != null) {
+ Test result = findTest(test);
+ if (perfResult != null && !result.getResult().equals(CtsTestStatus.FAIL)) {
// CTS result is passed in Summary++++Details format.
// Extract Summary and Details, and pass them.
Matcher m = mCtsLogPattern.matcher(perfResult);
if (m.find()) {
- Test result = findTest(test);
result.setResultStatus(CtsTestStatus.PASS);
result.setSummary(m.group(1));
result.setDetails(m.group(2));
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 43aaf98..6f4d42d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -63,7 +63,7 @@
private static final BatchRunConfiguration DEFAULT_CONFIG =
new BatchRunConfiguration("rgba8888d24s8", "unspecified", "window");
- private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 60000; // one minute
+ private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 10*60*1000; // ten minutes
private final String mPackageName;
private final String mName;
@@ -427,6 +427,7 @@
if (!mGotTestResult) {
result.allInstancesPassed = false;
result.errorMessages.put(mRunConfig, INCOMPLETE_LOG_MESSAGE);
+ CLog.i("Test %s failed as it ended before receiving result.", mCurrentTestId);
}
if (mLogData && mCurrentTestLog != null && mCurrentTestLog.length() > 0) {
@@ -477,6 +478,7 @@
mPendingResults.get(mCurrentTestId)
.errorMessages.put(mRunConfig, codeError + ": " + details);
mGotTestResult = true;
+ CLog.e("Got invalid result code '%s' for test %s", code, mCurrentTestId);
}
}
@@ -950,6 +952,7 @@
private void killDeqpProcess() throws DeviceNotAvailableException,
ProcessKillFailureException {
for (Integer processId : getDeqpProcessPids()) {
+ CLog.i("Killing deqp device process with ID %d", processId);
mDevice.executeShellCommand(String.format("kill -9 %d", processId));
}
@@ -958,6 +961,7 @@
// check that processes actually died
if (getDeqpProcessPids().iterator().hasNext()) {
// a process is still alive, killing failed
+ CLog.w("Failed to kill all deqp processes on device");
throw new ProcessKillFailureException();
}
}
@@ -1336,15 +1340,19 @@
UNRESPOSIVE_CMD_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
// Opening connection timed out
+ CLog.e("Opening connection timed out for command: '%s'", command);
throw new AdbComLinkOpenError("opening connection timed out", ex);
} catch (AdbCommandRejectedException ex) {
// Command rejected
+ CLog.e("Device rejected command: '%s'", command);
throw new AdbComLinkOpenError("command rejected", ex);
} catch (IOException ex) {
// shell command channel killed
+ CLog.e("Channel died for command: '%s'", command);
throw new AdbComLinkKilledError("command link killed", ex);
} catch (ShellCommandUnresponsiveException ex) {
// shell command halted
+ CLog.e("No output from command in %d ms: '%s'", UNRESPOSIVE_CMD_TIMEOUT_MS, command);
throw new AdbComLinkKilledError("command link hung", ex);
}
}
@@ -1460,11 +1468,14 @@
// interrupted, try to recover
if (interruptingError != null) {
if (interruptingError instanceof AdbComLinkOpenError) {
+ CLog.i("Recovering from comm link error");
mDeviceRecovery.recoverConnectionRefused();
} else if (interruptingError instanceof AdbComLinkKilledError) {
+ CLog.i("Recovering from comm link killed");
mDeviceRecovery.recoverComLinkKilled();
} else if (interruptingError instanceof RunInterruptedException) {
// external run interruption request. Terminate immediately.
+ CLog.i("Run termination requested. Throwing forward.");
throw (RunInterruptedException)interruptingError;
} else {
CLog.e(interruptingError);
@@ -1473,6 +1484,7 @@
// recoverXXX did not throw => recovery succeeded
} else if (!parser.wasSuccessful()) {
+ CLog.i("Parse not successful. Will attempt comm link recovery.");
mDeviceRecovery.recoverComLinkKilled();
// recoverXXX did not throw => recovery succeeded
}
@@ -1495,8 +1507,10 @@
// This is required so that a consistently crashing or non-existent tests will
// not cause futile (non-terminating) re-execution attempts.
if (mInstanceListerner.getCurrentTestId() != null) {
+ CLog.w("Test '%s' started, but not completed", onlyTest);
mInstanceListerner.abortTest(onlyTest, INCOMPLETE_LOG_MESSAGE);
} else {
+ CLog.w("Test '%s' could not start", onlyTest);
mInstanceListerner.abortTest(onlyTest, NOT_EXECUTABLE_LOG_MESSAGE);
}
} else if (wasTestExecuted) {
@@ -1827,6 +1841,7 @@
uninstallTestApk();
} else {
// Pass all tests if OpenGL ES version is not supported
+ CLog.i("Package %s not supported by the device. Tests trivially pass.", mPackageName);
fakePassTests(listener);
}
} catch (CapabilityQueryFailureException ex) {
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 375b1a0..2eb5145 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -470,6 +470,15 @@
'android.alarmclock.cts.SetAlarmTest#testAll',
'android.alarmclock.cts.SnoozeAlarmTest#testAll',
],
+ 'android.assist' : [
+ 'android.assist.cts.AssistantContentViewTest',
+ 'android.assist.cts.ExtraAssistDataTest',
+ 'android.assist.cts.FocusChangeTest',
+ 'android.assist.cts.LargeViewHierarchyTest',
+ 'android.assist.cts.ScreenshotTest',
+ 'android.assist.cts.TextViewTest',
+ 'android.assist.cts.WebViewTest',
+ ],
'android.calllog' : [
'android.calllog.cts.CallLogBackupTest#testSingleCallBackup',
],
@@ -487,9 +496,16 @@
'android.voicesettings' : [
'android.voicesettings.cts.ZenModeTest#testAll',
],
+ 'com.android.cts.systemui' : [
+ 'com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons',
+ ],
'com.android.cts.app.os' : [
'com.android.cts.app.os.OsHostTests#testNonExportedActivities',
],
+ 'com.android.cts.devicepolicy' : [
+ 'com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions',
+ 'com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions',
+ ],
'' : []}
def LogGenerateDescription(name):