diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-03-02 02:10:37 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-03-02 02:10:37 +0000 |
commit | 48f49e60427617866e082c89e5d38c9d8253b78b (patch) | |
tree | 458a8ec35befc478d59282e5c51c5a87dc94d858 | |
parent | f4832e39aeede40721b96e11124603ab09d1c862 (diff) | |
parent | 7ebd7233f5cd4f46fe103d4a5efed9f19f22aea8 (diff) | |
download | cts-android13-mainline-networking-release.tar.gz |
Snap for 9671667 from 7ebd7233f5cd4f46fe103d4a5efed9f19f22aea8 to mainline-networking-releaseaml_net_331812010aml_net_331710000android13-mainline-networking-release
Change-Id: I5ee4396518401054b0f239a99ccffbe666788e7a
184 files changed, 4598 insertions, 1367 deletions
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml index b9b0ddf21ec..d1a033937fe 100644 --- a/apps/CameraITS/config.yml +++ b/apps/CameraITS/config.yml @@ -32,6 +32,7 @@ TestBeds: lighting_ch: <controller-channel> camera: <camera-id> scene: <scene-name> # if <scene-name> left as-is runs all scenes + foldable_device: "False" # set to True if testing a foldable device - Name: TEST_BED_SENSOR_FUSION # Need 'sensor_fusion' in name for SF tests # Test configuration for sensor_fusion/test_sensor_fusion.py @@ -48,4 +49,4 @@ TestBeds: rotator_cntl: "arduino" # Note: only sensor fusion supports manual rotator_ch: <controller-channel> camera: <camera-id> - + foldable_device: "False" # set to True if testing a foldable device diff --git a/apps/CameraITS/tests/scene1_2/test_param_tonemap_mode.py b/apps/CameraITS/tests/scene1_2/test_param_tonemap_mode.py index 257ff3e3c61..92d6f865c51 100644 --- a/apps/CameraITS/tests/scene1_2/test_param_tonemap_mode.py +++ b/apps/CameraITS/tests/scene1_2/test_param_tonemap_mode.py @@ -85,7 +85,8 @@ class ParamTonemapModeTest(its_base_test.ItsBaseTest): props = cam.override_with_hidden_physical_camera_props(props) camera_properties_utils.skip_unless( camera_properties_utils.compute_target_exposure(props) and - camera_properties_utils.per_frame_control(props)) + camera_properties_utils.per_frame_control(props) and + camera_properties_utils.tonemap_mode(props, 0)) log_path = self.log_path # Load chart for scene diff --git a/apps/CameraITS/tests/scene3/test_3a_consistency.py b/apps/CameraITS/tests/scene3/test_3a_consistency.py index 71469fed15e..1ab129d026c 100644 --- a/apps/CameraITS/tests/scene3/test_3a_consistency.py +++ b/apps/CameraITS/tests/scene3/test_3a_consistency.py @@ -136,7 +136,7 @@ class ConsistencyTest(its_base_test.ItsBaseTest): fd_min = np.amin(fds) fd_max = np.amax(fds) if not np.isclose(fd_max, fd_min, _FD_TOL): - raise AssertionError(f'FD min: {fd_min}, max: {fd_min} TOL: {_FD_TOL}') + raise AssertionError(f'FD min: {fd_min}, max: {fd_max} TOL: {_FD_TOL}') for g in awb_gains: if np.isnan(g): raise AssertionError('AWB gain entry is not a number.') diff --git a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py index 7283f204882..184c9aa6a1e 100644 --- a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py +++ b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py @@ -15,6 +15,7 @@ import logging +import math import os.path from mobly import test_runner import numpy as np @@ -37,6 +38,8 @@ _PREVIEW_SIZE = (1920, 1080) # needs to pass the test for all resolutions within these aspect ratios. _AR_CHECKED_PRE_API_30 = ('4:3', '16:9', '18:9') _AR_DIFF_ATOL = 0.01 +# If RAW reference capture aspect ratio is ~4:3 or ~16:9, use JPEG, else RAW +_AR_FOR_JPEG_REFERENCE = (4/3, 16/9) def _check_skip_conditions(first_api_level, props): @@ -235,14 +238,34 @@ class AspectRatioAndCropTest(its_base_test.ItsBaseTest): debug = self.debug_mode # Converge 3A. - cam.do_3a() - req = capture_request_utils.auto_capture_request() + if camera_properties_utils.manual_sensor(props): + logging.debug('Manual sensor, using manual capture request') + s, e, _, _, f_d = cam.do_3a(get_results=True) + req = capture_request_utils.manual_capture_request( + s, e, f_distance=f_d) + else: + logging.debug('Using auto capture request') + cam.do_3a() + req = capture_request_utils.auto_capture_request() + + # For main camera: if RAW available, use it as ground truth, else JPEG + # For physical sub-camera: if RAW available, only use if not 4:3 or 16:9 + use_raw_fov = False + if raw_avlb: + pixel_array_w = props['android.sensor.info.pixelArraySize']['width'] + pixel_array_h = props['android.sensor.info.pixelArraySize']['height'] + logging.debug('Pixel array size: %dx%d', pixel_array_w, pixel_array_h) + raw_aspect_ratio = pixel_array_w / pixel_array_h + use_raw_fov = ( + fls_physical == fls_logical or not + any(math.isclose(raw_aspect_ratio, jpeg_ar, abs_tol=_AR_DIFF_ATOL) + for jpeg_ar in _AR_FOR_JPEG_REFERENCE) + ) - # If raw available, use as ground truth. ref_img_name_stem = f'{os.path.join(log_path, _NAME)}' ref_fov, cc_ct_gt, aspect_ratio_gt = ( image_fov_utils.find_fov_reference( - cam, req, props, raw_avlb, ref_img_name_stem)) + cam, req, props, use_raw_fov, ref_img_name_stem)) run_crop_test = full_or_better and raw_avlb if run_crop_test: @@ -273,7 +296,6 @@ class AspectRatioAndCropTest(its_base_test.ItsBaseTest): 'format': fmt_iter}] out_surface.append({'width': w_cmpr, 'height': h_cmpr, 'format': fmt_cmpr}) - cam.do_3a() cap = cam.do_capture(req, out_surface)[0] _check_basic_correctness(cap, fmt_iter, w_iter, h_iter) logging.debug('Captured %s with %s %dx%d. Compared size: %dx%d', 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 844807bfec7..592a6e6baf1 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 @@ -14,6 +14,7 @@ """Validate video aspect ratio, crop and FoV vs format.""" import logging +import math import os.path from mobly import test_runner @@ -33,6 +34,7 @@ _VIDEO_RECORDING_DURATION_SECONDS = 3 _FOV_PERCENT_RTOL = 0.15 # Relative tolerance on circle FoV % to expected. _AR_CHECKED_PRE_API_30 = ('4:3', '16:9', '18:9') _AR_DIFF_ATOL = 0.01 +_AR_FOR_JPEG_REFERENCE = (4/3, 16/9) _MAX_8BIT_IMGS = 255 _MAX_10BIT_IMGS = 1023 @@ -139,9 +141,9 @@ class VideoAspectRatioAndCropTest(its_base_test.ItsBaseTest): logging.debug('physical available focal lengths: %s', str(fls_physical)) # Check SKIP conditions. - vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial) + first_api_level = its_session_utils.get_first_api_level(self.dut.serial) camera_properties_utils.skip_unless( - vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL) + first_api_level >= its_session_utils.ANDROID13_API_LEVEL) # Load scene. its_session_utils.load_scene(cam, props, self.scene, @@ -160,13 +162,27 @@ class VideoAspectRatioAndCropTest(its_base_test.ItsBaseTest): req = capture_request_utils.auto_capture_request() ref_img_name_stem = f'{os.path.join(self.log_path, _NAME)}' - if raw_avlb and (fls_physical == fls_logical): - logging.debug('RAW') + # For main camera: if RAW available, use it as ground truth, else JPEG + # For physical sub-camera: if RAW available, only use if not 4:3 or 16:9 + if raw_avlb: + pixel_array_w = props['android.sensor.info.pixelArraySize']['width'] + pixel_array_h = props['android.sensor.info.pixelArraySize']['height'] + logging.debug('Pixel array size: %dx%d', pixel_array_w, pixel_array_h) + raw_aspect_ratio = pixel_array_w / pixel_array_h + if (fls_physical == fls_logical or not + any(math.isclose(raw_aspect_ratio, jpeg_ar, abs_tol=_AR_DIFF_ATOL) + for jpeg_ar in _AR_FOR_JPEG_REFERENCE)): + logging.debug('RAW') + use_raw_fov = True + else: + logging.debug('RAW available, but using JPEG as ground truth') + use_raw_fov = False else: logging.debug('JPEG') + use_raw_fov = False ref_fov, cc_ct_gt, aspect_ratio_gt = image_fov_utils.find_fov_reference( - cam, req, props, raw_avlb, ref_img_name_stem) + cam, req, props, use_raw_fov, ref_img_name_stem) run_crop_test = full_or_better and raw_avlb diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py index 34b2215f480..fbc882e22a7 100644 --- a/apps/CameraITS/tests/scene6/test_zoom.py +++ b/apps/CameraITS/tests/scene6/test_zoom.py @@ -244,11 +244,18 @@ class ZoomTest(its_base_test.ItsBaseTest): logging.debug('test TOLs: %s', str(test_tols)) # do captures over zoom range and find circles with cv2 - req = capture_request_utils.auto_capture_request() + if camera_properties_utils.manual_sensor(props): + logging.debug('Manual sensor, using manual capture request') + s, e, _, _, f_d = cam.do_3a(get_results=True) + req = capture_request_utils.manual_capture_request( + s, e, f_distance=f_d) + else: + logging.debug('Using auto capture request') + cam.do_3a() + req = capture_request_utils.auto_capture_request() for i, z in enumerate(z_list): logging.debug('zoom ratio: %.2f', z) req['android.control.zoomRatio'] = z - cam.do_3a() cap = cam.do_capture( req, {'format': 'yuv', 'width': size[0], 'height': size[1]}) img = image_processing_utils.convert_capture_to_rgb_image( diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py index dae63c3732e..a75ce5e8b17 100755 --- a/apps/CameraITS/tools/run_all_tests.py +++ b/apps/CameraITS/tools/run_all_tests.py @@ -55,6 +55,7 @@ TIME_KEY_START = 'start' TIME_KEY_END = 'end' VALID_CONTROLLERS = ('arduino', 'canakit') _INT_STR_DICT = {'11': '1_1', '12': '1_2'} # recover replaced '_' in scene def +_FRONT_CAMERA_ID = '1' # All possible scenes # Notes on scene names: @@ -337,6 +338,74 @@ def enable_external_storage(device_id): run(cmd) +def get_available_cameras(device_id, camera_id): + """Get available camera devices in the current state. + + Args: + device_id: Serial number of the device. + camera_id: Logical camera_id + + Returns: + List of all the available camera_ids. + """ + with its_session_utils.ItsSession( + device_id=device_id, + camera_id=camera_id) as cam: + props = cam.get_camera_properties() + props = cam.override_with_hidden_physical_camera_props(props) + unavailable_physical_cameras = cam.get_unavailable_physical_cameras( + camera_id) + unavailable_physical_ids = unavailable_physical_cameras[ + 'unavailablePhysicalCamerasArray'] + output = cam.get_camera_ids() + all_camera_ids = output['cameraIdArray'] + # Concat camera_id, physical camera_id and sub camera separator + unavailable_physical_ids = [f'{camera_id}.{s}' + for s in unavailable_physical_ids] + for i in unavailable_physical_ids: + if i in all_camera_ids: + all_camera_ids.remove(i) + logging.debug('available camera ids: %s', all_camera_ids) + return all_camera_ids + + +def get_unavailable_physical_cameras(device_id, camera_id): + """Get unavailable physical cameras in the current state. + + Args: + device_id: Serial number of the device. + camera_id: Logical camera device id + + Returns: + List of all the unavailable camera_ids. + """ + with its_session_utils.ItsSession( + device_id=device_id, + camera_id=camera_id) as cam: + unavailable_physical_cameras = cam.get_unavailable_physical_cameras( + camera_id) + unavailable_physical_ids = unavailable_physical_cameras[ + 'unavailablePhysicalCamerasArray'] + unavailable_physical_ids = [f'{camera_id}.{s}' + for s in unavailable_physical_ids] + logging.debug('Unavailable physical camera ids: %s', + unavailable_physical_ids) + return unavailable_physical_ids + + +def is_device_folded(device_id): + """Returns True if the foldable device is in folded state. + + Args: + device_id: Serial number of the foldable device. + """ + cmd = (f'adb -s {device_id} shell cmd device_state state') + result = subprocess.getoutput(cmd) + if 'CLOSED' in result: + return True + return False + + def main(): """Run all the Camera ITS automated tests. @@ -390,6 +459,19 @@ def main(): # Enable external storage on DUT to send summary report to CtsVerifier.apk enable_external_storage(device_id) + # Check whether the dut is foldable or not + testing_foldable_device = True if test_params_content[ + 'foldable_device'] == 'True' else False + available_camera_ids_to_test_foldable = [] + if testing_foldable_device: + logging.debug('Testing foldable device.') + # Check the state of foldable device. True if device is folded, + # false if the device is opened. + device_folded = is_device_folded(device_id) + # list of available camera_ids to be tested in device state + available_camera_ids_to_test_foldable = get_available_cameras( + device_id, _FRONT_CAMERA_ID) + config_file_test_key = config_file_contents['TestBeds'][0]['Name'].lower() if TEST_KEY_TABLET in config_file_test_key: tablet_id = get_device_serial_number('tablet', config_file_contents) @@ -417,6 +499,12 @@ def main(): scenes = [_GROUPED_SCENES[s] if s in _GROUPED_SCENES else s for s in scenes] scenes = np.hstack(scenes).tolist() scenes = sorted(set(scenes), key=scenes.index) + # List of scenes to be executed in folded state will have '_folded' + # prefix. This will help distinguish the test results from folded vs + # open device state for front camera_ids. + folded_device_scenes = [] + for scene in scenes: + folded_device_scenes.append(f'{scene}_folded') logging.info('Running ITS on device: %s, camera(s): %s, scene(s): %s', device_id, camera_id_combos, scenes) @@ -428,9 +516,48 @@ def main(): auto_scene_switch = False logging.info('No tablet: manual, sensor_fusion, or scene5 testing.') + folded_prompted = False + opened_prompted = False for camera_id in camera_id_combos: test_params_content['camera'] = camera_id results = {} + unav_cameras = [] + # Get the list of unavailable cameras in current device state. + # These camera_ids should not be tested in current device state. + if testing_foldable_device: + unav_cameras = get_unavailable_physical_cameras( + device_id, _FRONT_CAMERA_ID) + + if testing_foldable_device: + device_state = 'folded' if device_folded else 'opened' + + testing_folded_front_camera = (testing_foldable_device and + device_folded and + _FRONT_CAMERA_ID in camera_id) + + # Raise an assertion error if there is any camera unavailable in + # current device state. Usually scenes with suffix 'folded' will + # be executed in folded state. + if (testing_foldable_device and + _FRONT_CAMERA_ID in camera_id and camera_id in unav_cameras): + raise AssertionError( + f'Camera {camera_id} is unavailable in device state {device_state}' + f' and cannot be tested with device {device_state}!') + + if (testing_folded_front_camera and camera_id not in unav_cameras + and not folded_prompted): + folded_prompted = True + input('\nYou are testing a foldable device in folded state.' + 'Please make sure the device is folded and press <ENTER>' + 'after positioning properly.\n') + + if (testing_foldable_device and + not device_folded and _FRONT_CAMERA_ID in camera_id and + camera_id not in unav_cameras and not opened_prompted): + opened_prompted = True + input('\nYou are testing a foldable device in opened state.' + 'Please make sure the device is unfolded and press <ENTER>' + 'after positioning properly.\n') # Run through all scenes if user does not supply one and config file doesn't # have specific scene name listed. @@ -452,9 +579,35 @@ def main(): if not per_camera_scenes: raise ValueError('No valid scene specified for this camera.') + # Folded state scenes will have 'folded' suffix only for + # front cameras since rear cameras are common in both folded + # and unfolded state. + foldable_per_camera_scenes = [] + if testing_folded_front_camera: + if camera_id not in available_camera_ids_to_test_foldable: + raise AssertionError(f'camera {camera_id} is not available.') + for s in per_camera_scenes: + foldable_per_camera_scenes.append(f'{s}_folded') + + if foldable_per_camera_scenes: + per_camera_scenes = foldable_per_camera_scenes + logging.info('camera: %s, scene(s): %s', camera_id, per_camera_scenes) - for s in _ALL_SCENES: + + if testing_folded_front_camera: + all_scenes = [f'{s}_folded' for s in _ALL_SCENES] + else: + all_scenes = _ALL_SCENES + + for s in all_scenes: results[s] = {RESULT_KEY: RESULT_NOT_EXECUTED} + + # assert device folded testing scenes with suffix 'folded' + if testing_foldable_device and 'folded' in s: + if not device_folded: + raise AssertionError('Device should be folded during' + ' testing scenes with suffix "folded"') + # A subdir in topdir will be created for each camera_id. All scene test # output logs for each camera id will be stored in this subdir. # This output log path is a mobly param : LogPath @@ -464,7 +617,6 @@ def main(): os.mkdir(mobly_output_logs_path) tot_pass = 0 for s in per_camera_scenes: - test_params_content['scene'] = s results[s]['TEST_STATUS'] = [] results[s][METRICS_KEY] = [] @@ -473,14 +625,22 @@ def main(): scene_test_summary = f'Cam{camera_id} {s}' + '\n' mobly_scene_output_logs_path = os.path.join(mobly_output_logs_path, s) + # Since test directories do not have 'folded' in the name, we need + # to remove that suffix for the path of the scenes to be loaded + # on the tablets + testing_scene = s + if 'folded' in s: + testing_scene = s.split('_folded')[0] + test_params_content['scene'] = testing_scene if auto_scene_switch: # Copy scene images onto the tablet - if s not in ['scene0']: - load_scenes_on_tablet(s, tablet_id) + if 'scene0' not in testing_scene: + load_scenes_on_tablet(testing_scene, tablet_id) else: # Check manual scenes for correctness - if s not in ['scene0'] and not testing_sensor_fusion_with_controller: - check_manual_scenes(device_id, camera_id, s, mobly_output_logs_path) + if 'scene0' not in testing_scene and not testing_sensor_fusion_with_controller: + check_manual_scenes(device_id, camera_id, testing_scene, + mobly_output_logs_path) scene_test_list = [] config_file_contents['TestBeds'][0]['TestParams'] = test_params_content @@ -497,19 +657,21 @@ def main(): logging.info('Using %s as temporary config yml file', new_yml_file_name) if camera_id.rfind(its_session_utils.SUB_CAMERA_SEPARATOR) == -1: scene_dir = os.listdir( - os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', s)) + os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', testing_scene)) for file_name in scene_dir: if file_name.endswith('.py') and 'test' in file_name: scene_test_list.append(file_name) else: # sub-camera - if SUB_CAMERA_TESTS.get(s): - scene_test_list = [f'{test}.py' for test in SUB_CAMERA_TESTS[s]] + if SUB_CAMERA_TESTS.get(testing_scene): + scene_test_list = [f'{test}.py' for test in SUB_CAMERA_TESTS[ + testing_scene]] else: scene_test_list = [] scene_test_list.sort() # Run tests for scene - logging.info('Running tests for %s with camera %s', s, camera_id) + logging.info('Running tests for %s with camera %s', + testing_scene, camera_id) num_pass = 0 num_skip = 0 num_not_mandated_fail = 0 @@ -525,7 +687,8 @@ def main(): else: cmd = [ 'python3', - os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', s, test), + os.path.join(os.environ['CAMERA_ITS_TOP'], 'tests', + testing_scene, test), '-c', '%s' % new_yml_file_name ] @@ -589,7 +752,8 @@ def main(): os.remove(MOBLY_TEST_SUMMARY_TXT_FILE) logging.info('%s %s/%s', return_string, s, test) test_name = test.split('/')[-1].split('.')[0] - results[s]['TEST_STATUS'].append({'test':test_name,'status':return_string.strip()}) + results[s]['TEST_STATUS'].append({'test': test_name, + 'status': return_string.strip()}) if test_mpc_req: results[s][METRICS_KEY].append(test_mpc_req) msg_short = '%s %s' % (return_string, test) diff --git a/apps/CameraITS/utils/camera_properties_utils.py b/apps/CameraITS/utils/camera_properties_utils.py index 261c03e92d2..44aa510c49c 100644 --- a/apps/CameraITS/utils/camera_properties_utils.py +++ b/apps/CameraITS/utils/camera_properties_utils.py @@ -557,6 +557,20 @@ def edge_mode(props, mode): 'android.edge.availableEdgeModes'] +def tonemap_mode(props, mode): + """Returns whether a device supports the tonemap mode. + + Args: + props: Camera properties object. + mode: Integer, indicating the tonemap mode to check for availability. + + Return: + Boolean. + """ + return 'android.edge.availableToneMapModes' in props and mode in props[ + 'android.tonemap.availableToneMapModes'] + + def yuv_reprocess(props): """Returns whether a device supports YUV reprocessing. diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py index a846306dbe2..b1fb77a72c3 100644 --- a/apps/CameraITS/utils/its_session_utils.py +++ b/apps/CameraITS/utils/its_session_utils.py @@ -453,6 +453,21 @@ class ItsSession(object): self.sock.settimeout(self.SOCK_TIMEOUT) return data['objValue'] + def get_camera_ids(self): + """Returns the list of all camera_ids. + + Returns: + List of camera ids on the device. + """ + cmd = {'cmdName': 'getCameraIds'} + self.sock.send(json.dumps(cmd).encode() + '\n'.encode()) + timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT + self.sock.settimeout(timeout) + data, _ = self.__read_response_from_socket() + if data['tag'] != 'cameraIds': + raise error_util.CameraItsError('Invalid command response') + return data['objValue'] + def get_unavailable_physical_cameras(self, camera_id): """Get the unavailable physical cameras ids. diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml index 7cd577cf7e1..6c464b1bad3 100644 --- a/apps/CtsVerifier/AndroidManifest.xml +++ b/apps/CtsVerifier/AndroidManifest.xml @@ -3026,8 +3026,7 @@ <activity android:name=".camera.bokeh.CameraBokehActivity" android:label="@string/camera_bokeh_test" android:configChanges="keyboardHidden|screenSize" - android:exported="true" - android:screenOrientation="landscape"> + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.cts.intent.category.MANUAL_TEST" /> @@ -5275,6 +5274,8 @@ <meta-data android:name="test_category" android:value="@string/test_category_tv"/> <meta-data android:name="test_required_features" android:value="android.software.leanback"/> + <meta-data android:name="test_required_configs" + android:value="config_hdmi_source"/> <meta-data android:name="display_mode" android:value="multi_display_mode" /> <meta-data android:name="ApiTest" diff --git a/apps/CtsVerifier/res/layout-port/OWNERS b/apps/CtsVerifier/res/layout-port/OWNERS new file mode 100644 index 00000000000..f4217d97594 --- /dev/null +++ b/apps/CtsVerifier/res/layout-port/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 41727 = per-file camera_*.xml +# Bug component: 41727 = per-file cam_*.xml + +per-file camera_*.xml = file:platform/frameworks/av:/camera/OWNERS +per-file cam_*.xml = file:platform/frameworks/av:/camera/OWNERS
\ No newline at end of file diff --git a/apps/CtsVerifier/res/layout-port/cb_main.xml b/apps/CtsVerifier/res/layout-port/cb_main.xml new file mode 100644 index 00000000000..9a3ae1fb0ad --- /dev/null +++ b/apps/CtsVerifier/res/layout-port/cb_main.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Portrait orientation layout for the Camera Bokeh activity. + Provides a different view of the controls than the default (landscape) + layout. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="0dp" + android:layout_weight="1" > + + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="fill_parent" + android:layout_weight="2" > + + <Spinner + android:id="@+id/cameras_selection" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/test_label" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:padding="2dp" + android:textSize="16sp" + android:gravity="left" /> + + <Button + android:id="@+id/next_button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/next_button_text" /> + + </LinearLayout> + + </LinearLayout> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="0dp" + android:layout_weight="1" > + + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="fill_parent" + android:layout_weight="3" > + + <TextureView + android:id="@+id/preview_view" + android:layout_height="0dp" + android:layout_width="fill_parent" + android:layout_weight="3" /> + <TextView + android:id="@+id/preview_label" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:padding="2dp" + android:textSize="16sp" + android:gravity="center" /> + + </LinearLayout> + + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="fill_parent" + android:layout_weight="3" > + + <ImageView + android:id="@+id/image_view" + android:layout_height="0dp" + android:layout_width="fill_parent" + android:layout_weight="3" /> + <TextView + android:id="@+id/image_label" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:padding="2dp" + android:textSize="16sp" + android:gravity="center" /> + + </LinearLayout> + + </LinearLayout> + + <include layout="@layout/pass_fail_buttons" /> + +</LinearLayout> diff --git a/apps/CtsVerifier/res/layout/OWNERS b/apps/CtsVerifier/res/layout/OWNERS new file mode 100644 index 00000000000..349a259b0b4 --- /dev/null +++ b/apps/CtsVerifier/res/layout/OWNERS @@ -0,0 +1,7 @@ +# Bug component: 41727 = per-file camera_*.xml +# Bug component: 41727 = per-file cam_*.xml +# Bug component: 41727 = per-file co_main.xml,ci_main.xml,cb_main.xml,cf_main.xml + +per-file camera_*.xml = file:platform/frameworks/av:/camera/OWNERS +per-file cam_*.xml = file:platform/frameworks/av:/camera/OWNERS +per-file co_main.xml,ci_main.xml,cb_main.xml,cf_main.xml = file:platform/frameworks/av:/camera/OWNERS
\ No newline at end of file diff --git a/apps/CtsVerifier/res/layout/co_main.xml b/apps/CtsVerifier/res/layout/co_main.xml index e3ddf491656..ad402549ee6 100644 --- a/apps/CtsVerifier/res/layout/co_main.xml +++ b/apps/CtsVerifier/res/layout/co_main.xml @@ -62,7 +62,8 @@ android:id="@+id/format_view" android:layout_height="fill_parent" android:layout_width="fill_parent" - android:layout_weight="4" /> + android:layout_weight="4" + android:scaleType="fitCenter" /> <TextView android:id="@+id/format_label" 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 2e5046aca67..c97edc752ee 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java @@ -744,9 +744,9 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity { class LoopbackLatencyRequirements { public static final int MPC_NONE = 0; - public static final int MPC_R = 1; - public static final int MPC_S = 2; - public static final int MPC_T = 3; + public static final int MPC_R = Build.VERSION_CODES.R; + public static final int MPC_S = Build.VERSION_CODES.S; + public static final int MPC_T = Build.VERSION_CODES.TIRAMISU; String mResultsString = new String(); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java index 9e27cb3e1ac..73fc7428579 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java @@ -68,7 +68,9 @@ public class RingerModeActivity extends InteractiveVerifierActivity { private final static String PKG = "com.android.cts.verifier"; private final static long TIME_TO_PLAY = 2000; private final static int MP3_TO_PLAY = R.raw.testmp3; - private final static int ASYNC_TIMING_TOLERANCE_MS = 50; + // TODO replace sleeps with blocking receiver of ACTION_VOLUME_CHANGED intent for + // volume operations (AudioManager.setStreamVolume and .adjustVolume) + private static final int ASYNC_TIMING_TOLERANCE_MS = 150; private AudioManager mAudioManager; private boolean mHasVibrator; @@ -781,7 +783,7 @@ public class RingerModeActivity extends InteractiveVerifierActivity { // 7 to 1: success mAudioManager.setStreamVolume( AudioManager.STREAM_SYSTEM, 1, AudioManager.FLAG_ALLOW_RINGER_MODES); - if (1 != mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM)) { + if (1 != mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM)) { setFailed(); return; } @@ -911,6 +913,11 @@ public class RingerModeActivity extends InteractiveVerifierActivity { } mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0); + try { + Thread.sleep(ASYNC_TIMING_TOLERANCE_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } // volume raise mAudioManager.setStreamVolume(stream, 1, 0); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java index 55791c61fdb..3a7bc72cc56 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/bokeh/CameraBokehActivity.java @@ -15,16 +15,8 @@ */ package com.android.cts.verifier.camera.bokeh; -import com.android.cts.verifier.PassFailButtons; -import com.android.cts.verifier.R; - -import com.android.ex.camera2.blocking.BlockingCameraManager; -import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; -import com.android.ex.camera2.blocking.BlockingStateCallback; -import com.android.ex.camera2.blocking.BlockingSessionCallback; - import android.app.AlertDialog; -import android.content.res.Configuration; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -32,6 +24,7 @@ import android.graphics.ColorFilter; import android.graphics.ColorMatrixColorFilter; import android.graphics.ImageFormat; import android.graphics.Matrix; +import android.graphics.PointF; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; @@ -43,9 +36,9 @@ import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.Capability; import android.hardware.camera2.params.StreamConfigurationMap; -import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.media.ImageReader; import android.os.Bundle; @@ -56,9 +49,10 @@ import android.util.Size; import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; -import android.view.View; +import android.view.OrientationEventListener; import android.view.Surface; import android.view.TextureView; +import android.view.View; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -68,14 +62,19 @@ import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; -import android.content.Context; -import java.lang.Math; +import com.android.cts.verifier.PassFailButtons; +import com.android.cts.verifier.R; +import com.android.ex.camera2.blocking.BlockingCameraManager; +import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; +import com.android.ex.camera2.blocking.BlockingSessionCallback; +import com.android.ex.camera2.blocking.BlockingStateCallback; + import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.Set; @@ -131,6 +130,8 @@ public class CameraBokehActivity extends PassFailButtons.Activity private HashMap<String, ArrayList<Capability>> mTestCases = new HashMap<>(); private int mCurrentCameraIndex = -1; private String mCameraId; + private int mCameraSensorOrientation; + private int mCameraLensFacing; private CameraCaptureSession mCaptureSession; private CameraDevice mCameraDevice; @@ -204,6 +205,8 @@ public class CameraBokehActivity extends PassFailButtons.Activity } }; + private OrientationEventListener mOrientationEventListener = null; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -305,6 +308,13 @@ public class CameraBokehActivity extends PassFailButtons.Activity mBlockingCameraManager = new BlockingCameraManager(mCameraManager); mCameraListener = new BlockingStateCallback(); + + mOrientationEventListener = new OrientationEventListener(getApplicationContext()) { + @Override + public void onOrientationChanged(int orientation) { + configurePreviewTextureTransform(); + } + }; } /** @@ -417,6 +427,12 @@ public class CameraBokehActivity extends PassFailButtons.Activity } @Override + public void onDestroy() { + super.onDestroy(); + mOrientationEventListener.disable(); + } + + @Override public String getTestDetails() { StringBuilder reportBuilder = new StringBuilder(); reportBuilder.append("Tested combinations:\n"); @@ -550,7 +566,11 @@ public class CameraBokehActivity extends PassFailButtons.Activity mCurrentColorFilter = null; mImageView.clearColorFilter(); } + mImageView.setImageBitmap(bitmap); + if (format == ImageFormat.YUV_420_888) { + configureImageViewTransform(); + } } }); } @@ -611,6 +631,10 @@ public class CameraBokehActivity extends PassFailButtons.Activity // Update untested cameras mUntestedCameras.remove("All combinations for Camera " + mCameraId); + mCameraSensorOrientation = + mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); + mCameraLensFacing = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING); + StreamConfigurationMap config = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG); @@ -691,9 +715,8 @@ public class CameraBokehActivity extends PassFailButtons.Activity } } - private void configurePreviewTextureTransform() { + private int getDisplayRotation() { int rotation = getWindowManager().getDefaultDisplay().getRotation(); - Configuration config = getResources().getConfiguration(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; @@ -701,42 +724,117 @@ public class CameraBokehActivity extends PassFailButtons.Activity case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } - Matrix matrix = mPreviewView.getTransform(null); - int deviceOrientation = Configuration.ORIENTATION_PORTRAIT; - if ((degrees % 180 == 0 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) || - (degrees % 180 == 90 && config.orientation == Configuration.ORIENTATION_PORTRAIT)) { - deviceOrientation = Configuration.ORIENTATION_LANDSCAPE; - } - int effectiveWidth = mPreviewSize.getWidth(); - int effectiveHeight = mPreviewSize.getHeight(); - if (deviceOrientation == Configuration.ORIENTATION_PORTRAIT) { - int temp = effectiveWidth; - effectiveWidth = effectiveHeight; - effectiveHeight = temp; + return degrees; + } + + /** + * Calculate the matrix required to center the preview with the correct rotation, such that + * the image is not cropped and either the width or height perfectly fills the available space. + * This is to compensate for the default behavior of TextureView, which is to not rotate the + * image and to completely fill the texture in both dimensions. + */ + private void configurePreviewTextureTransform() { + int displayRotation = getDisplayRotation(); + + Matrix matrix = new Matrix(); + + mPreviewView.getSurfaceTexture().setDefaultBufferSize(mPreviewSize.getWidth(), + mPreviewSize.getHeight()); + RectF viewRect = new RectF(0, 0, mPreviewView.getWidth(), mPreviewView.getHeight()); + + float expectedPreviewWidth, expectedPreviewHeight; + if ((360 + mCameraSensorOrientation - displayRotation) % 180 == 0) { + expectedPreviewWidth = mPreviewSize.getWidth(); + expectedPreviewHeight = mPreviewSize.getHeight(); + } else { + expectedPreviewWidth = mPreviewSize.getHeight(); + expectedPreviewHeight = mPreviewSize.getWidth(); } - RectF viewRect = new RectF(0, 0, mPreviewTexWidth, mPreviewTexHeight); - RectF bufferRect = new RectF(0, 0, effectiveWidth, effectiveHeight); - float centerX = viewRect.centerX(); - float centerY = viewRect.centerY(); - bufferRect.offset(centerX - bufferRect.centerX(), - centerY - bufferRect.centerY()); + float viewAspectRatio = viewRect.width() / viewRect.height(); + float imageAspectRatio = expectedPreviewWidth / expectedPreviewHeight; + final PointF scale; - matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL); + if (viewAspectRatio > imageAspectRatio) { + scale = new PointF((viewRect.height() / viewRect.width()) + * ((float) mPreviewSize.getHeight() / (float) mPreviewSize.getWidth()), 1f); + } else { + scale = new PointF(1f, (viewRect.width() / viewRect.height()) + * ((float) mPreviewSize.getWidth() / (float) mPreviewSize.getHeight())); + } + + if (displayRotation % 180 != 0) { + float multiplier = viewAspectRatio > imageAspectRatio + ? expectedPreviewWidth / expectedPreviewHeight + : expectedPreviewHeight / expectedPreviewWidth; + scale.x *= multiplier; + scale.y *= multiplier; + } - matrix.postRotate((360 - degrees) % 360, centerX, centerY); - if ((degrees % 180) == 90) { - int temp = effectiveWidth; - effectiveWidth = effectiveHeight; - effectiveHeight = temp; + matrix.setScale(scale.x, scale.y, viewRect.centerX(), viewRect.centerY()); + if (displayRotation != 0) { + matrix.postRotate(360 - displayRotation, viewRect.centerX(), viewRect.centerY()); } - // Scale to fit view, avoiding any crop - float scale = Math.min(mPreviewTexWidth / (float) effectiveWidth, - mPreviewTexHeight / (float) effectiveHeight); - matrix.postScale(scale, scale, centerX, centerY); mPreviewView.setTransform(matrix); } + + /** + * Calculate the matrix required to center the capture with the correct rotation, such that + * the image is not cropped and either the width or height perfectly fills the available space. + * This is to compensate for the default behavior of ImageView, which is to not rotate the + * image and to render it in its original size, positioned at 0, 0. + */ + private void configureImageViewTransform() { + int displayRotation = getDisplayRotation(); + int rotation = (360 + mCameraSensorOrientation - displayRotation) % 360; + if (mCameraLensFacing == CameraMetadata.LENS_FACING_FRONT) { + rotation = (mCameraSensorOrientation + displayRotation) % 360; + } + + Matrix matrix = new Matrix(); + + RectF viewRect = new RectF(0, 0, mImageView.getMeasuredWidth(), + mImageView.getMeasuredHeight()); + + float expectedPreviewWidth, expectedPreviewHeight; + if (rotation % 180 == 0) { + expectedPreviewWidth = mPreviewSize.getWidth(); + expectedPreviewHeight = mPreviewSize.getHeight(); + } else { + expectedPreviewWidth = mPreviewSize.getHeight(); + expectedPreviewHeight = mPreviewSize.getWidth(); + } + + final PointF scale = new PointF(0, 0); + + float widthRatio = expectedPreviewWidth / viewRect.width(); + float heightRatio = expectedPreviewHeight / viewRect.height(); + if (widthRatio / heightRatio > 1.0f) { + // Scale width to fit + scale.x = 1.0f / widthRatio; + scale.y = 1.0f / widthRatio; + } else { + // Scale height to fit + scale.x = 1.0f / heightRatio; + scale.y = 1.0f / heightRatio; + } + + matrix.setScale(scale.x, scale.y, 0, 0); + if (rotation % 360 != 0) { + matrix.postRotate(rotation, 0, 0); + } + + RectF imageRect = new RectF(0, 0, mPreviewSize.getWidth(), mPreviewSize.getHeight()); + matrix.mapRect(imageRect, imageRect); + matrix.postTranslate(-imageRect.left, -imageRect.top); + matrix.postTranslate(viewRect.width() / 2 - imageRect.width() / 2, + viewRect.height() / 2 - imageRect.height() / 2); + + mImageView.setScaleType(ImageView.ScaleType.MATRIX); + mImageView.setImageMatrix(matrix); + } + /** * Starts a background thread and its {@link Handler}. */ @@ -762,6 +860,8 @@ public class CameraBokehActivity extends PassFailButtons.Activity private void startPreview() { try { + mOrientationEventListener.disable(); + if (mPreviewSize == null || !mPreviewSize.equals(mNextCombination.mPreviewSize) || mYuvImageReader == null) { mPreviewSize = mNextCombination.mPreviewSize; @@ -800,6 +900,10 @@ public class CameraBokehActivity extends PassFailButtons.Activity mStillCaptureRequest = mStillCaptureRequestBuilder.build(); mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mCameraHandler); + + if (mOrientationEventListener.canDetectOrientation()) { + mOrientationEventListener.enable(); + } } catch (CameraAccessException e) { e.printStackTrace(); } 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 703779f550d..8682dd75693 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 @@ -276,7 +276,10 @@ public class ItsService extends Service implements SensorEventListener { private volatile boolean mNeedsLockedAWB = false; private volatile boolean mDoAE = true; private volatile boolean mDoAF = true; - private Set<Pair<String, String>> mUnavailablePhysicalCameras; + private final LinkedBlockingQueue<String> unavailableEventQueue = new LinkedBlockingQueue<>(); + private final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue = + new LinkedBlockingQueue<>(); + private Set<String> mUnavailablePhysicalCameras; class MySensorEvent { @@ -286,6 +289,31 @@ public class ItsService extends Service implements SensorEventListener { public float values[]; } + CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() { + @Override + public void onCameraAvailable(String cameraId) { + super.onCameraAvailable(cameraId); + } + + @Override + public void onCameraUnavailable(String cameraId) { + super.onCameraUnavailable(cameraId); + unavailableEventQueue.offer(cameraId); + } + + @Override + public void onPhysicalCameraAvailable(String cameraId, String physicalCameraId) { + super.onPhysicalCameraAvailable(cameraId, physicalCameraId); + unavailablePhysicalCamEventQueue.remove(new Pair<>(cameraId, physicalCameraId)); + } + + @Override + public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) { + super.onPhysicalCameraUnavailable(cameraId, physicalCameraId); + unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId)); + } + }; + static class VideoRecordingObject { private static final int INVALID_FRAME_RATE = -1; @@ -470,6 +498,9 @@ public class ItsService extends Service implements SensorEventListener { public void openCameraDevice(String cameraId) throws ItsException { Logt.i(TAG, String.format("Opening camera %s", cameraId)); + // Get initial physical unavailable callbacks without opening camera + mCameraManager.registerAvailabilityCallback(ac, mCameraHandler); + try { if (mMemoryQuota == -1) { // Initialize memory quota on this device @@ -495,15 +526,22 @@ public class ItsService extends Service implements SensorEventListener { } try { - mUnavailablePhysicalCameras = getUnavailablePhysicalCameras(); + mUnavailablePhysicalCameras = getUnavailablePhysicalCameras( + unavailablePhysicalCamEventQueue, cameraId); + Log.i(TAG, "Unavailable cameras:" + Arrays.asList(mUnavailablePhysicalCameras.toString())); mCamera = mBlockingCameraManager.openCamera(cameraId, mCameraListener, mCameraHandler); mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId); - + // The camera should be in available->unavailable state. + unavailableEventQueue.clear(); boolean isLogicalCamera = hasCapability( CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA); if (isLogicalCamera) { Set<String> physicalCameraIds = mCameraCharacteristics.getPhysicalCameraIds(); for (String id : physicalCameraIds) { + if (mUnavailablePhysicalCameras.contains(id)) { + Log.i(TAG, "Physical camera id not available: " + id); + continue; + } mPhysicalCameraChars.put(id, mCameraManager.getCameraCharacteristics(id)); } } @@ -512,6 +550,8 @@ public class ItsService extends Service implements SensorEventListener { throw new ItsException("Failed to open camera", e); } catch (BlockingOpenException e) { throw new ItsException("Failed to open camera (after blocking)", e); + } catch (Exception e) { + throw new ItsException("Failed to get unavailable physical cameras", e); } mSocketRunnableObj.sendResponse("cameraOpened", ""); } @@ -522,6 +562,7 @@ public class ItsService extends Service implements SensorEventListener { Logt.i(TAG, "Closing camera"); mCamera.close(); mCamera = null; + mCameraManager.unregisterAvailabilityCallback(ac); } } catch (Exception e) { throw new ItsException("Failed to close device"); @@ -861,6 +902,8 @@ public class ItsService extends Service implements SensorEventListener { } else if ("getMaxCamcorderProfileSize".equals(cmdObj.getString("cmdName"))) { String cameraId = cmdObj.getString("cameraId"); doGetMaxCamcorderProfileSize(cameraId); + } else if ("getAvailablePhysicalCameraProperties".equals(cmdObj.getString("cmdName"))) { + doGetAvailablePhysicalCameraProperties(); } else { throw new ItsException("Unknown command: " + cmd); } @@ -961,6 +1004,25 @@ public class ItsService extends Service implements SensorEventListener { } } + public void sendResponse(String tag, HashMap<String, CameraCharacteristics> props) + throws ItsException { + try { + JSONArray jsonSurfaces = new JSONArray(); + int n = props.size(); + for (String s : props.keySet()) { + JSONObject jsonSurface = new JSONObject(); + jsonSurface.put(s, ItsSerializer.serialize(props.get(s))); + jsonSurfaces.put(jsonSurface); + } + Object objs[] = new Object[2]; + objs[0] = "availablePhysicalCameraProperties"; + objs[1] = jsonSurfaces; + mSerializerQueue.put(objs); + } catch (Exception e) { + throw new ItsException("Interrupted: ", e); + } + } + public void sendVideoRecordingObject(VideoRecordingObject obj) throws ItsException { try { @@ -1139,6 +1201,27 @@ public class ItsService extends Service implements SensorEventListener { } } + private void doGetAvailablePhysicalCameraProperties() throws ItsException { + mSocketRunnableObj.sendResponse("availablePhysicalCameraProperties", mPhysicalCameraChars); + } + + private Set<String> getUnavailablePhysicalCameras( + LinkedBlockingQueue<Pair<String, String>> queue, String cameraId) throws Exception { + Set<String> unavailablePhysicalCameras = new HashSet<String>(); + while (true) { + Pair<String, String> unavailableIdCombo = queue.poll( + AVAILABILITY_TIMEOUT_MS, java.util.concurrent.TimeUnit.MILLISECONDS); + if (unavailableIdCombo == null) { + // No more entries in the queue. Break out of the loop and return. + break; + } + if (cameraId.equals(unavailableIdCombo.first)) { + unavailablePhysicalCameras.add(unavailableIdCombo.second); + } + }; + return unavailablePhysicalCameras; + } + private void doGetCameraIds() throws ItsException { if (mItsCameraIdList == null) { mItsCameraIdList = ItsUtils.getItsCompatibleCameraIds(mCameraManager); @@ -1223,10 +1306,8 @@ public class ItsService extends Service implements SensorEventListener { try { JSONArray cameras = new JSONArray(); JSONObject jsonObj = new JSONObject(); - for (Pair<String, String> p : mUnavailablePhysicalCameras) { - if (cameraId.equals(p.first)) { - cameras.put(p.second); - } + for (String p : mUnavailablePhysicalCameras) { + cameras.put(p); } jsonObj.put("unavailablePhysicalCamerasArray", cameras); Log.i(TAG, "unavailablePhysicalCameras : " + diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java index 66e632b8ee8..88cd7d4b160 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/orientation/CameraOrientationActivity.java @@ -18,10 +18,13 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.graphics.Matrix; +import android.graphics.RectF; import android.hardware.Camera; +import android.hardware.Camera.CameraInfo; import android.os.Bundle; import android.os.Handler; import android.util.Log; +import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; @@ -78,6 +81,9 @@ implements OnClickListener, SurfaceHolder.Callback { private int mState = STATE_OFF; private boolean mSizeAdjusted; + private int mPreviewRotation; + private int mPictureRotation; + private StringBuilder mReportBuilder = new StringBuilder(); private final TreeSet<String> mTestedCombinations = new TreeSet<String>(); private final TreeSet<String> mUntestedCombinations = new TreeSet<String>(); @@ -287,11 +293,27 @@ implements OnClickListener, SurfaceHolder.Callback { // set preview orientation int degrees = mPreviewOrientations.get(mNextPreviewOrientation); - mCamera.setDisplayOrientation(degrees); - android.hardware.Camera.CameraInfo info = - new android.hardware.Camera.CameraInfo(); - android.hardware.Camera.getCameraInfo(mCurrentCameraId, info); + CameraInfo info = new CameraInfo(); + Camera.getCameraInfo(mCurrentCameraId, info); + int displayRotation = getWindowManager().getDefaultDisplay().getRotation(); + switch (displayRotation) { + case Surface.ROTATION_90: degrees += 90; break; + case Surface.ROTATION_180: degrees += 180; break; + case Surface.ROTATION_270: degrees += 270; break; + } + degrees %= 360; + + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + mPictureRotation = (info.orientation + degrees) % 360; + mPreviewRotation = (360 - mPictureRotation) % 360; // compensate the mirror + } else { // back-facing + mPictureRotation = (info.orientation - degrees + 360) % 360; + mPreviewRotation = mPictureRotation; + } + + mCamera.setDisplayOrientation(mPreviewRotation); + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { TextView cameraExtraLabel = (TextView) findViewById(R.id.instruction_extra_text); @@ -484,30 +506,31 @@ implements OnClickListener, SurfaceHolder.Callback { @Override public void onPreviewFrame(byte[] data, Camera camera) { // adjust camera preview to match output image's aspect ratio - if(!mSizeAdjusted && mState == STATE_PREVIEW) { - int viewWidth = mFormatView.getWidth(); - int viewHeight = mFormatView.getHeight(); - int newWidth, newHeight; + if (!mSizeAdjusted && mState == STATE_PREVIEW) { + int viewWidth = mFormatView.getMeasuredWidth(); + int viewHeight = mFormatView.getMeasuredHeight(); - if (viewWidth == 0 || viewHeight == 0){ + if (viewWidth == 0 || viewHeight == 0) { return; } - if (mPreviewOrientations.get(mNextPreviewOrientation) == 0 - || mPreviewOrientations.get(mNextPreviewOrientation) == 180) { - // make preview width same as output image width, - // then calculate height using output image's height/width ratio - newWidth = viewWidth; - newHeight = (int) (viewWidth * ((double) mOptimalPreviewSize.height / - (double) mOptimalPreviewSize.width)); - } - else { - newHeight = viewHeight; - newWidth = (int) (viewHeight * ((double) mOptimalPreviewSize.height / - (double) mOptimalPreviewSize.width)); + Matrix m = new Matrix(Matrix.IDENTITY_MATRIX); + RectF previewRect; + if (mPreviewRotation == 0 || mPreviewRotation == 180) { + previewRect = new RectF(0, 0, mOptimalPreviewSize.width, + mOptimalPreviewSize.height); + } else { + previewRect = new RectF(0, 0, mOptimalPreviewSize.height, + mOptimalPreviewSize.width); } - - LayoutParams layoutParams = new LayoutParams(newWidth, newHeight); + m.setRectToRect(previewRect, + new RectF(0, 0, viewWidth, viewHeight), + Matrix.ScaleToFit.CENTER); + RectF dstRect = new RectF(); + m.mapRect(dstRect, previewRect); + + LayoutParams layoutParams = + new LayoutParams((int) dstRect.width(), (int) dstRect.height()); mCameraView.setLayoutParams(layoutParams); mSizeAdjusted = true; mTakePictureButton.setEnabled(true); @@ -523,7 +546,6 @@ implements OnClickListener, SurfaceHolder.Callback { Bitmap inputImage; inputImage = BitmapFactory.decodeByteArray(data, 0, data.length); - int degrees = mPreviewOrientations.get(mNextPreviewOrientation); android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mCurrentCameraId, info); @@ -531,7 +553,6 @@ implements OnClickListener, SurfaceHolder.Callback { if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { // mirror the image along vertical axis mirrorX = new float[] {-1, 0, 0, 0, 1, 1, 0, 0, 1}; - degrees = (360 - degrees) % 360; // compensate the mirror } else { // leave image the same via identity matrix mirrorX = new float[] {1, 0, 0, 0, 1, 0, 0, 0, 1}; @@ -541,7 +562,7 @@ implements OnClickListener, SurfaceHolder.Callback { Matrix matrixMirrorX = new Matrix(); matrixMirrorX.setValues(mirrorX); Matrix mat = new Matrix(); - mat.postRotate(degrees); + mat.postRotate(mPictureRotation); mat.postConcat(matrixMirrorX); Bitmap inputImageAdjusted = Bitmap.createBitmap(inputImage, diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java index 26be3212b57..e258c132e7d 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java @@ -57,6 +57,7 @@ public class WifiLockdownTestActivity extends PassFailButtons.TestListActivity { private static final String DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI_ID = "DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI"; + private WifiManager mWifiManager; private WifiConfigCreator mConfigCreator; private ButtonInfo[] mSwitchLockdownOffButtonInfos; private ButtonInfo[] mSwitchLockdownOnButtonInfos; @@ -64,9 +65,9 @@ public class WifiLockdownTestActivity extends PassFailButtons.TestListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WifiManager wifiManager = TestAppSystemServiceFactory.getWifiManager(this, + mWifiManager = TestAppSystemServiceFactory.getWifiManager(this, DeviceAdminTestReceiver.class); - mConfigCreator = new WifiConfigCreator(this, wifiManager); + mConfigCreator = new WifiConfigCreator(this, mWifiManager); setContentView(R.layout.wifi_lockdown); setInfoResources(R.string.device_owner_wifi_lockdown_test, R.string.device_owner_wifi_lockdown_info, 0); @@ -159,23 +160,27 @@ public class WifiLockdownTestActivity extends PassFailButtons.TestListActivity { R.string.device_owner_wifi_config_unlocked_removal_test, R.string.device_owner_wifi_config_unlocked_removal_test_info, mSwitchLockdownOffButtonInfos)); - adapter.add(Utils.createInteractiveTestItem(this, - DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI_ID, - R.string.device_owner_disallow_sharing_admin_configure_wifi, - R.string.device_owner_disallow_sharing_admin_configure_wifi_info, - new ButtonInfo[] { + + boolean isDppSupported = mWifiManager.isEasyConnectSupported(); + if (isDppSupported) { + adapter.add(Utils.createInteractiveTestItem(this, + DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI_ID, + R.string.device_owner_disallow_sharing_admin_configure_wifi, + R.string.device_owner_disallow_sharing_admin_configure_wifi_info, + new ButtonInfo[] { new ButtonInfo( R.string.device_owner_user_restriction_set, CommandReceiverActivity.createSetCurrentUserRestrictionIntent( - UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, true)), + UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, true)), new ButtonInfo( R.string.device_owner_settings_go, new Intent(Settings.ACTION_WIFI_SETTINGS)), new ButtonInfo( R.string.device_owner_user_restriction_unset, CommandReceiverActivity.createSetCurrentUserRestrictionIntent( - UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, false)) - })); + UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, false)) + })); + } } private int convertKeyManagement(int radioButtonId) { diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java index dcf0a960a10..ae1684f6a78 100644 --- a/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java +++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/DisableAnimationRule.java @@ -16,55 +16,9 @@ package com.android.compatibility.common.util; -import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +public class DisableAnimationRule extends OverrideAnimationScaleRule { -import androidx.annotation.NonNull; - -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -public class DisableAnimationRule extends BeforeAfterRule { - @NonNull - private final GlobalSetting mWindowAnimationScaleSetting = new GlobalSetting( - "window_animation_scale"); - @NonNull - private final GlobalSetting mTransitionAnimationScaleSetting = new GlobalSetting( - "transition_animation_scale"); - @NonNull - private final GlobalSetting mAnimatorDurationScaleSetting = new GlobalSetting( - "animator_duration_scale"); - - @Override - protected void onBefore(Statement base, Description description) throws Throwable { - mWindowAnimationScaleSetting.put("0"); - mTransitionAnimationScaleSetting.put("0"); - mAnimatorDurationScaleSetting.put("0"); - } - - @Override - protected void onAfter(Statement base, Description description) throws Throwable { - mWindowAnimationScaleSetting.restore(); - mTransitionAnimationScaleSetting.restore(); - mAnimatorDurationScaleSetting.restore(); - } - - private static class GlobalSetting { - @NonNull - private final String mName; - - private String mInitialValue; - - public GlobalSetting(@NonNull String name) { - mName = name; - } - - public void put(@NonNull String value) { - mInitialValue = runShellCommand("settings get global " + mName); - runShellCommand("settings put global " + mName + " " + value); - } - - public void restore() { - runShellCommand("settings put global " + mName + " " + mInitialValue); - } + public DisableAnimationRule() { + super(0); } } diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java index c3b6900c64e..e8ed8c7e7a1 100644 --- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java +++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java @@ -1479,6 +1479,14 @@ public class MediaUtils { if (screenSize < (FIRST_SDK_IS_AT_LEAST_R ? 3.3 : 2.5)) return false; if (screenSize > 8.0) return false; if (!hasDeviceGotBattery()) return false; + // handheld nature is not exposed to package manager, so for now, + // in addition to physical screen size, the following checks are + // also required: + if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) return false; + if (isWatch()) return false; + if (isTv()) return false; + if (isAutomotive()) return false; + if (isPc()) return false; return true; } @@ -1487,6 +1495,14 @@ public class MediaUtils { if (screenSize < 7.0) return false; if (screenSize > 18.0) return false; if (!hasDeviceGotBattery()) return false; + // tablet nature is not exposed to package manager, so for now, + // in addition to physical screen size, the following checks are + // also required: + if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) return false; + if (isWatch()) return false; + if (isTv()) return false; + if (isAutomotive()) return false; + if (isPc()) return false; return true; } diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.java new file mode 100644 index 00000000000..2d50bfa91cd --- /dev/null +++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/OverrideAnimationScaleRule.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 com.android.compatibility.common.util; + +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; + +import androidx.annotation.NonNull; + +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + + +public class OverrideAnimationScaleRule extends BeforeAfterRule { + + @NonNull + private final GlobalSetting mWindowAnimationScaleSetting = new GlobalSetting( + "window_animation_scale"); + @NonNull + private final GlobalSetting mTransitionAnimationScaleSetting = new GlobalSetting( + "transition_animation_scale"); + @NonNull + private final GlobalSetting mAnimatorDurationScaleSetting = new GlobalSetting( + "animator_duration_scale"); + + private final float mAnimationScale; + + public OverrideAnimationScaleRule(float animationScale) { + mAnimationScale = animationScale; + } + + @Override + protected void onBefore(Statement base, Description description) { + var value = Float.toString(mAnimationScale); + mWindowAnimationScaleSetting.put(value); + mTransitionAnimationScaleSetting.put(value); + mAnimatorDurationScaleSetting.put(value); + } + + @Override + protected void onAfter(Statement base, Description description) { + mWindowAnimationScaleSetting.restore(); + mTransitionAnimationScaleSetting.restore(); + mAnimatorDurationScaleSetting.restore(); + } + + private static class GlobalSetting { + @NonNull + private final String mName; + + private String mInitialValue; + + public GlobalSetting(@NonNull String name) { + mName = name; + } + + public void put(@NonNull String value) { + mInitialValue = runShellCommand("settings get global " + mName); + runShellCommand("settings put global " + mName + " " + value); + } + + public void restore() { + runShellCommand("settings put global " + mName + " " + mInitialValue); + } + } +} 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 c0dfae1b9b2..5d792d93789 100644 --- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java +++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java @@ -29,6 +29,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -37,6 +38,9 @@ import javax.xml.parsers.DocumentBuilderFactory; public final class CompatChangesValidConfigTest extends CompatChangeGatingTestCase { + private static final long RESTRICT_STORAGE_ACCESS_FRAMEWORK = 141600225L; + private static final String FEATURE_WATCH = "android.hardware.type.watch"; + private static final Set<String> OVERRIDES_ALLOWLIST = ImmutableSet.of( // This change id will sometimes remain enabled if an instrumentation test fails. "ALLOW_TEST_API_ACCESS" @@ -114,6 +118,15 @@ public final class CompatChangesValidConfigTest extends CompatChangeGatingTestCa changes.add(change); } } + + // RESTRICT_STORAGE_ACCESS_FRAMEWORK not supported on wear + if (getDevice().hasFeature(FEATURE_WATCH)) { + for (Iterator<Change> it = changes.iterator(); it.hasNext();) { + if (it.next().changeId == RESTRICT_STORAGE_ACCESS_FRAMEWORK) { + it.remove(); + } + } + } return changes; } 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 478cde28351..46f1b478230 100644 --- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java +++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java @@ -758,6 +758,8 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test { new ImmutableMap.Builder<String, ImmutableSet<String>>() .put("/apex/com.android.btservices/app/Bluetooth/Bluetooth.apk", BLUETOOTH_APK_IN_APEX_BURNDOWN_LIST) + .put("/apex/com.android.btservices/app/BluetoothArc/BluetoothArc.apk", + 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", diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java index 9e12ad04492..a31088616c3 100644 --- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java +++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java @@ -35,6 +35,7 @@ import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Path; import android.provider.DocumentsProvider; import android.provider.Settings; +import android.support.test.uiautomator.Configurator; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiScrollable; @@ -50,6 +51,7 @@ import androidx.core.os.BuildCompat; import com.android.cts.documentclient.MyActivity.Result; import java.io.File; +import java.time.Duration; import java.util.List; /** @@ -73,6 +75,9 @@ public class DocumentsClientTest extends DocumentsClientTestCase { private static final String STORAGE_AUTHORITY = "com.android.externalstorage.documents"; private static final String DEFAULT_DEVICE_NAME = "Internal storage"; + private static final Duration SCROLL_ACKNOWLEDGEMENT_TIMEOUT = Duration.ofMillis(500); + private long mOriginalScrollAcknowledgementTimeout; + private UiSelector findRootListSelector() throws UiObjectNotFoundException { return new UiSelector().resourceId( getDocumentsUiPackageId() + ":id/container_roots").childSelector( @@ -193,12 +198,24 @@ public class DocumentsClientTest extends DocumentsClientTestCase { public void setUp() throws Exception { super.setUp(); deleteTestDirectory(); + + // Extending ScrollAcknowledgmentTimeout so that we can avoid a bug in ui automator + // (b/266374704) and stabilize scrolling with UiScrollable. + mOriginalScrollAcknowledgementTimeout = + Configurator.getInstance().getScrollAcknowledgmentTimeout(); + if (SCROLL_ACKNOWLEDGEMENT_TIMEOUT.toMillis() > mOriginalScrollAcknowledgementTimeout) { + Configurator.getInstance() + .setScrollAcknowledgmentTimeout(SCROLL_ACKNOWLEDGEMENT_TIMEOUT.toMillis()); + } } @Override public void tearDown() throws Exception { super.tearDown(); deleteTestDirectory(); + + Configurator.getInstance() + .setScrollAcknowledgmentTimeout(mOriginalScrollAcknowledgementTimeout); } public void testOpenSimple() throws Exception { diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java index 92f53ac21b8..a41c4b9f084 100644 --- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java +++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java @@ -337,6 +337,7 @@ public class EncryptionAppTest extends InstrumentationTestCase { assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE); if (Environment.isExternalStorageEmulated()) { + pollForExternalStorageMountedState(); assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState()); final File expected = new File( @@ -360,6 +361,15 @@ public class EncryptionAppTest extends InstrumentationTestCase { ceFile::exists); } + private void pollForExternalStorageMountedState() { + for (int i = 0; i < 10; i++) { + if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) { + break; + } + SystemClock.sleep(500); + } + } + private void assertQuery(int count, int flags) throws Exception { final Intent intent = new Intent(TEST_ACTION); assertEquals("activity", count, mPm.queryIntentActivities(intent, flags).size()); diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java index 2ec37fdc71f..c1fa58b3410 100644 --- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java +++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java @@ -602,7 +602,7 @@ public class ManagedProfileTest extends BaseManagedProfileTest { assertActivityInForeground("android/com.android.internal.app.ResolverActivity", userId); } catch (AssertionError e) { CLog.v("ResolverActivity is not the default: " + e); - assertActivityInForeground(resolveActivity("android.intent.action.SEND"), userId); + assertActivityInForeground(getCustomResolverActivity(), userId); } } @@ -647,4 +647,16 @@ public class ManagedProfileTest extends BaseManagedProfileTest { return outputs[1]; } + + private String getCustomResolverActivity() throws Exception { + final String[] outputs = getDevice().executeShellCommand( + "cmd overlay lookup android android:string/config_customResolverActivity") + .split("\n"); + + String customResolverActivity = resolveActivity("android.intent.action.SEND"); + if (outputs != null && outputs.length >= 1 && outputs[0] != null && !outputs[0].isEmpty()) { + customResolverActivity = outputs[0]; + } + return customResolverActivity; + } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java index a5be8bfe4c4..38765c2fb28 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java @@ -56,6 +56,7 @@ public enum CecOperand { VENDOR_COMMAND(0x89), GIVE_DEVICE_VENDOR_ID(0x8c), MENU_REQUEST(0x8d), + MENU_STATUS(0x8e), GIVE_POWER_STATUS(0x8f), REPORT_POWER_STATUS(0x90), GET_MENU_LANGUAGE(0x91), diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java index 19d2c757d0e..e1d9216f7e2 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java @@ -95,10 +95,12 @@ public final class HdmiCecGeneralProtocolTest extends BaseHdmiCecCtsTest { throws Exception { // DeviceDiscoveryAction will send GIVE_OSD_NAME and GIVE_DEVICE_VENDOR_ID // HotplugDetectionAction will send GIVE_PHYSICAL_ADDRESS + // PowerStatusMonitorAction will send GIVE_POWER_STATUS List<CecOperand> excludeOperands = new ArrayList<>(); excludeOperands.add(CecOperand.GIVE_PHYSICAL_ADDRESS); excludeOperands.add(CecOperand.GIVE_DEVICE_VENDOR_ID); excludeOperands.add(CecOperand.GIVE_OSD_NAME); + excludeOperands.add(CecOperand.GIVE_POWER_STATUS); hdmiCecClient.sendCecMessage(message, params); // Default timeout for the incoming command to arrive in response to a request is 2 secs diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java index cf9ea396177..3ca4ee0e277 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java @@ -461,10 +461,12 @@ public final class HdmiCecPowerStatusTest extends BaseHdmiCecCtsTest { TimeUnit.SECONDS.sleep(waitSeconds); waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON); - // Send <UCP> [Power]. DUT should go to standby. + // Send <UCP> [Power]. DUT should remain in ON state. hdmiCecClient.sendUserControlPressAndRelease( source, HdmiCecConstants.CEC_KEYCODE_POWER, false); - waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY); + waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON); + + sendDeviceToSleep(); // Send <UCP> [Power]. DUT should wakeup. hdmiCecClient.sendUserControlPressAndRelease( diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java index 93d81003e30..7cd2e1f87ba 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java @@ -66,7 +66,7 @@ public final class HdmiCecStartupTest extends BaseHdmiCecCtsTest { CecOperand.DEVICE_VENDOR_ID, CecOperand.GIVE_POWER_STATUS, CecOperand.GET_MENU_LANGUAGE, CecOperand.ACTIVE_SOURCE, CecOperand.REQUEST_ACTIVE_SOURCE, CecOperand.GIVE_PHYSICAL_ADDRESS, - CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS)); + CecOperand.REPORT_POWER_STATUS, CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS)); allowedMessages.addAll(expectedMessages); device.reboot(); diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java index 96e026dc196..d44f44ccaaa 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecVendorCommandsTest.java @@ -22,8 +22,8 @@ import android.hdmicec.cts.BaseHdmiCecCtsTest; import android.hdmicec.cts.CecMessage; import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiControlManagerUtility; -import android.hdmicec.cts.LogicalAddress; import android.hdmicec.cts.LogHelper; +import android.hdmicec.cts.LogicalAddress; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; @@ -31,9 +31,9 @@ import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import org.junit.Rule; +import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.runner.RunWith; -import org.junit.Test; /** HDMI CEC test to verify device vendor specific commands (Section 11.2.9) */ @RunWith(DeviceJUnit4ClassRunner.class) @@ -157,7 +157,7 @@ public final class HdmiCecVendorCommandsTest extends BaseHdmiCecCtsTest { String params = CecMessage.formatParams(VENDOR_ID); params += CecMessage.formatParams("010203"); hdmiCecClient.sendCecMessage( - LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params); + hdmiCecClient.getSelfDevice(), CecOperand.VENDOR_COMMAND_WITH_ID, params); LogHelper.assertLog( device, TEST_LOG_TAG, "Received vendor command with correct vendor ID"); @@ -176,7 +176,8 @@ public final class HdmiCecVendorCommandsTest extends BaseHdmiCecCtsTest { LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER); String params = CecMessage.formatParams("010203"); - hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params); + hdmiCecClient.sendCecMessage( + hdmiCecClient.getSelfDevice(), CecOperand.VENDOR_COMMAND, params); LogHelper.assertLog(device, TEST_LOG_TAG, "Received vendor command without vendor ID"); } finally { @@ -194,7 +195,8 @@ public final class HdmiCecVendorCommandsTest extends BaseHdmiCecCtsTest { LogHelper.waitForLog(getDevice(), TEST_LOG_TAG, 10, REGISTERED_LISTENER); String params = CecMessage.formatParams("010203"); - hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.VENDOR_COMMAND, params); + hdmiCecClient.sendCecMessage( + hdmiCecClient.getSelfDevice(), CecOperand.VENDOR_COMMAND, params); LogHelper.assertLog(device, TEST_LOG_TAG, "Received vendor command without vendor ID"); } finally { @@ -214,7 +216,7 @@ public final class HdmiCecVendorCommandsTest extends BaseHdmiCecCtsTest { String params = CecMessage.formatParams(VENDOR_ID); params += CecMessage.formatParams("010203"); hdmiCecClient.sendCecMessage( - LogicalAddress.TV, CecOperand.VENDOR_COMMAND_WITH_ID, params); + hdmiCecClient.getSelfDevice(), CecOperand.VENDOR_COMMAND_WITH_ID, params); LogHelper.assertLogDoesNotContain( device, TEST_LOG_TAG, "Received vendor command with correct vendor ID"); diff --git a/hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/AppValidationTest.java b/hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/AppValidationTest.java index 6654d5b7ff7..5dc7dd8d320 100644 --- a/hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/AppValidationTest.java +++ b/hostsidetests/incrementalinstall/appvalidator/src/android/incrementalinstall/inrementaltestappvalidation/AppValidationTest.java @@ -39,6 +39,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + @RunWith(AndroidJUnit4.class) @AppModeFull public class AppValidationTest { @@ -87,6 +92,17 @@ public class AppValidationTest { assertEquals(isIncfsInstallation, new PathChecker().isIncFsPath(installedAppInfo.installationPath)); assertEquals(versionCode, installedAppInfo.versionCode); + // Read the whole file to make sure it's streamed. + readFullFile(new File(installedAppInfo.installationPath, "base.apk")); + } + + private static void readFullFile(File file) throws IOException { + try (InputStream inputStream = new FileInputStream(file)) { + byte[] buffer = new byte[1024]; + while (inputStream.read(buffer) != -1) { + // ignore + } + } } private void launchTestApp() throws Exception { diff --git a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java index 81e3304a849..c050b2cf2ea 100644 --- a/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java +++ b/hostsidetests/incrementalinstall/src/android/incrementalinstall/cts/IncrementalInstallTest.java @@ -23,6 +23,7 @@ import static android.incrementalinstall.common.Consts.SupportedComponents.ON_CR import static android.incrementalinstall.common.Consts.SupportedComponents.ON_CREATE_COMPONENT_2; import static android.incrementalinstall.common.Consts.SupportedComponents.UNCOMPRESSED_NATIVE_COMPONENT; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -32,6 +33,7 @@ import android.platform.test.annotations.LargeTest; import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.Log; +import com.android.tradefed.device.TestDeviceOptions; import com.android.tradefed.log.LogUtil; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -95,12 +97,18 @@ public class IncrementalInstallTest extends BaseHostJUnit4Test { private static final String INSTALL_SUCCESS_OUTPUT = "Success"; private static final long DEFAULT_TEST_TIMEOUT_MS = 60 * 1000L; private static final long DEFAULT_MAX_TIMEOUT_TO_OUTPUT_MS = 60 * 1000L; // 1min + private static final long DEFAULT_ADB_TIMEOUT_MS = 5 * 60 * 1000L; // 5mins private final int TEST_APP_V1_VERSION = 1; private final int TEST_APP_V2_VERSION = 2; private CompatibilityBuildHelper mBuildHelper; @Before public void setup() throws Exception { + // Increase default timeout to 5 mins to accommodate for slow restarting devices. + TestDeviceOptions options = new TestDeviceOptions(); + options.setAdbCommandTimeout(DEFAULT_ADB_TIMEOUT_MS); + getDevice().setOptions(options); + assumeTrue(hasIncrementalFeature()); mBuildHelper = new CompatibilityBuildHelper(getBuild()); assumeTrue(adbBinarySupportsIncremental()); @@ -254,9 +262,9 @@ public class IncrementalInstallTest extends BaseHostJUnit4Test { getDevice().executeAdbCommand("push", getFilePathFromBuildInfo(TEST_APP_DYNAMIC_CODE_NAME + SIG_SUFFIX), deviceLocalPath); - getDevice().executeShellCommand( + assertEquals("Success\n", getDevice().executeShellCommand( String.format("pm install-incremental -p %s %s", TEST_APP_PACKAGE_NAME, - deviceLocalPath + TEST_APP_DYNAMIC_CODE_NAME)); + deviceLocalPath + TEST_APP_DYNAMIC_CODE_NAME))); // Verify still on Incremental. verifyInstallationTypeAndVersion(TEST_APP_PACKAGE_NAME, /* isIncfs= */ true, TEST_APP_V1_VERSION); diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java index 55c431cb092..351b2d074ba 100644 --- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java +++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java @@ -79,6 +79,7 @@ import static android.scopedstorage.cts.lib.TestUtils.installAppWithStoragePermi import static android.scopedstorage.cts.lib.TestUtils.isAppInstalled; import static android.scopedstorage.cts.lib.TestUtils.listAs; import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider; +import static android.scopedstorage.cts.lib.TestUtils.pollForPermission; import static android.scopedstorage.cts.lib.TestUtils.queryAudioFile; import static android.scopedstorage.cts.lib.TestUtils.queryFile; import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending; @@ -1321,7 +1322,7 @@ public class ScopedStorageDeviceTest extends ScopedStorageBaseDeviceTest { getExifMetadataFromRawResource(R.raw.img_with_metadata); try (InputStream in = getContext().getResources().openRawResource(R.raw.img_with_metadata); - FileOutputStream out = new FileOutputStream(imgFile)) { + FileOutputStream out = new FileOutputStream(imgFile)) { // Dump the image we have to external storage FileUtils.copy(in, out); // Sync file to disk to ensure file is fully written to the lower fs. @@ -1335,6 +1336,8 @@ public class ScopedStorageDeviceTest extends ScopedStorageBaseDeviceTest { // Grant A_M_L and verify access to sensitive data grantPermission(APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION); + pollForPermission(APP_C.getPackageName(), + Manifest.permission.ACCESS_MEDIA_LOCATION, /* granted */ true); HashMap<String, String> exifFromTestApp = readExifMetadataFromTestApp(APP_C, imgFile.getPath()); assertExifMetadataMatch(exifFromTestApp, originalExif); @@ -1344,6 +1347,8 @@ public class ScopedStorageDeviceTest extends ScopedStorageBaseDeviceTest { APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION); // revokePermission waits for permission status to be updated, but MediaProvider still // needs to get permission change callback and clear its permission cache. + pollForPermission(APP_C.getPackageName(), + Manifest.permission.ACCESS_MEDIA_LOCATION, /* granted */ false); Thread.sleep(500); exifFromTestApp = readExifMetadataFromTestApp(APP_C, imgFile.getPath()); assertExifMetadataMismatch(exifFromTestApp, originalExif); @@ -1352,6 +1357,8 @@ public class ScopedStorageDeviceTest extends ScopedStorageBaseDeviceTest { grantPermission(APP_C.getPackageName(), Manifest.permission.ACCESS_MEDIA_LOCATION); // grantPermission waits for permission status to be updated, but MediaProvider still // needs to get permission change callback and clear its permission cache. + pollForPermission(APP_C.getPackageName(), + Manifest.permission.ACCESS_MEDIA_LOCATION, /* granted */ true); Thread.sleep(500); exifFromTestApp = readExifMetadataFromTestApp(APP_C, imgFile.getPath()); assertExifMetadataMatch(exifFromTestApp, originalExif); diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java index 814363d7e56..44e616dfccc 100644 --- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java +++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java @@ -207,7 +207,7 @@ public class KernelConfigTest extends BaseHostJUnit4Test { break; } /* Samsung Exynos SoCs */ - else if (line.startsWith("EXYNOS") || line.startsWith("S5E")) { + else if (line.startsWith("EXYNOS")) { hardware = line; break; } @@ -237,8 +237,6 @@ public class KernelConfigTest extends BaseHostJUnit4Test { put("EXYNOS7872", null); put("EXYNOS7885", null); put("EXYNOS9610", null); - put("S5E8825", null); - put("S5E9925", null); put("Kirin980", null); put("Kirin970", null); put("Kirin810", null); diff --git a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java index b71617405ca..5d2beb3c41b 100644 --- a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java +++ b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java @@ -59,10 +59,24 @@ import java.time.Duration; import java.util.Arrays; import java.util.List; -/** Host-side CTS tests for the location time zone manager service. */ +/** + * Host-side CTS tests for the location time zone manager service. There are plenty of unit tests + * for individual components but manufacturers don't have to run them. This test is intended to + * provide confidence that the specific device configuration is likely to work as it should, i.e. + * this tests the actual location_time_zone_manager service on a given device. + * + * <p>Because there are a large set of possibilities, this test has to handle them all: + * <ul> + * <li>location_time_zone_manager service disabled</li> + * <li>location_time_zone_manager service enabled, but no LTZPs configured</li> + * <li>location_time_zone_manager service enabled, with LTZPs configured</li> + * </ul> + */ @RunWith(DeviceJUnit4ClassRunner.class) public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { + private static final String NON_EXISTENT_TZPS_APP_PACKAGE = "foobar"; + private boolean mOriginalLocationEnabled; private boolean mOriginalAutoDetectionEnabled; private boolean mOriginalGeoDetectionEnabled; @@ -80,8 +94,8 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { mLocationTimeZoneManagerShellHelper = new LocationTimeZoneManagerShellHelper(shellCommandExecutor); - // Confirm the service being tested is present. It can be turned off, in which case there's - // nothing to test. + // Confirm the service being tested is present. It can be turned off permanently in config, + // in which case there's nothing about it to test. mLocationTimeZoneManagerShellHelper.assumeLocationTimeZoneManagerIsPresent(); // Install the app that hosts the fake providers. @@ -96,28 +110,50 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { mDeviceConfigPreTestState = mDeviceConfigShellHelper.setSyncModeForTest( SYNC_DISABLED_MODE_UNTIL_REBOOT, NAMESPACE_SYSTEM_TIME); - // All tests start with the location_time_zone_manager disabled so that providers can be - // configured. + // These original values try to record the raw value of the settings before the test ran: + // they may be ignored by the location_time_zone_manager service when they have no meaning. + // Unfortunately, we cannot tell if the value returned is the result of setting defaults or + // real values, which means we may not return things exactly as they were. To do better + // would require looking at raw settings values and use internal knowledge of settings keys. + mOriginalAutoDetectionEnabled = mTimeZoneDetectorShellHelper.isAutoDetectionEnabled(); + mOriginalGeoDetectionEnabled = mTimeZoneDetectorShellHelper.isGeoDetectionEnabled(); + mLocationTimeZoneManagerShellHelper.stop(); - // Make sure locations is enabled, otherwise the geo detection feature will be disabled - // whatever the geolocation detection setting is set to. + // Make sure location is enabled, otherwise the geo detection feature cannot operate. mOriginalLocationEnabled = mLocationShellHelper.isLocationEnabledForCurrentUser(); if (!mOriginalLocationEnabled) { mLocationShellHelper.setLocationEnabledForCurrentUser(true); } - // Make sure automatic time zone detection is enabled, otherwise the geo detection feature - // will be disabled whatever the geolocation detection setting is set to. - mOriginalAutoDetectionEnabled = mTimeZoneDetectorShellHelper.isAutoDetectionEnabled(); - if (!mOriginalAutoDetectionEnabled) { - mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); + // Restart the location_time_zone_manager with a do-nothing test config; some settings + // values cannot be set when the service knows that the settings won't be used. Devices + // can be encountered with the location_time_zone_manager enabled but with no providers + // installed. Starting the service with a valid-looking test provider config means we know + // settings changes will be accepted regardless of the real config. + String testPrimaryLocationTimeZoneProviderPackageName = NON_EXISTENT_TZPS_APP_PACKAGE; + String testSecondaryLocationTimeZoneProviderPackageName = null; + mLocationTimeZoneManagerShellHelper.startWithTestProviders( + testPrimaryLocationTimeZoneProviderPackageName, + testSecondaryLocationTimeZoneProviderPackageName, + false /* recordProviderStates */); + + // Begin all tests with auto detection turned off. + if (mOriginalAutoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(false); } - // On devices with no location time zone providers (e.g. AOSP), we cannot turn geo detection - // on until the test LTZPs are configured as the time_zone_detector will refuse. - mOriginalGeoDetectionEnabled = mTimeZoneDetectorShellHelper.isGeoDetectionEnabled(); + // We set the device settings so that location detection will be used. + if (!mOriginalGeoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + } + // All tests begin with the location_time_zone_manager stopped so that fake providers can be + // configured. + mLocationTimeZoneManagerShellHelper.stop(); + + // Make sure the fake provider APK install started above has completed before tests try to + // use the fake providers. FakeTimeZoneProviderAppShellHelper fakeTimeZoneProviderAppShellHelper = new FakeTimeZoneProviderAppShellHelper(shellCommandExecutor); // Delay until the fake TZPS app can be found. @@ -135,24 +171,33 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { return; } - // Reset the geoDetectionEnabled state while there is at least one LTZP configured: this - // setting cannot be modified if there are no LTZPs on the device, e.g. on AOSP. - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(mOriginalGeoDetectionEnabled); - - // Turn off the service before we reset configuration, otherwise it will restart itself - // repeatedly. + // Restart the location_time_zone_manager with a test config so that the device can be set + // back to the starting state regardless of how the test left things. mLocationTimeZoneManagerShellHelper.stop(); + String testPrimaryLocationTimeZoneProviderPackageName = NON_EXISTENT_TZPS_APP_PACKAGE; + String testSecondaryLocationTimeZoneProviderPackageName = null; + mLocationTimeZoneManagerShellHelper.startWithTestProviders( + testPrimaryLocationTimeZoneProviderPackageName, + testSecondaryLocationTimeZoneProviderPackageName, + false /* recordProviderStates */); + + if (mTimeZoneDetectorShellHelper.isGeoDetectionEnabled() != mOriginalGeoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(mOriginalGeoDetectionEnabled); + } - // Reset settings and server flags as best we can. if (mTimeZoneDetectorShellHelper.isAutoDetectionEnabled() != mOriginalAutoDetectionEnabled) { mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(mOriginalAutoDetectionEnabled); } + + // Everything else can be reset without worrying about the providers. + mLocationTimeZoneManagerShellHelper.stop(); + mLocationShellHelper.setLocationEnabledForCurrentUser(mOriginalLocationEnabled); mDeviceConfigShellHelper.restoreDeviceConfigStateForTest(mDeviceConfigPreTestState); - // Attempt to start the service. It may not start if there are no providers configured, - // but that is ok. + // Attempt to start the service without test providers. It may not start if there are no + // providers configured, but that is ok. mLocationTimeZoneManagerShellHelper.start(); } @@ -165,7 +210,10 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { testPrimaryLocationTimeZoneProviderPackageName, testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates */); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + + // Turn on auto detection, which should activate the location time zone algorithm. + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); + mPrimaryFakeTimeZoneProviderShellHelper.assertCreated(); mSecondaryFakeTimeZoneProviderShellHelper.assertNotCreated(); @@ -219,7 +267,8 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { testPrimaryLocationTimeZoneProviderPackageName, testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates */); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + // Turn on auto detection, which should activate the location time zone algorithm. + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); mPrimaryFakeTimeZoneProviderShellHelper.assertCreated(); mSecondaryFakeTimeZoneProviderShellHelper.assertNotCreated(); @@ -280,7 +329,8 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { testPrimaryLocationTimeZoneProviderPackageName, testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates */); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + // Turn on auto detection, which should activate the location time zone algorithm. + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); mPrimaryFakeTimeZoneProviderShellHelper.assertCreated(); mSecondaryFakeTimeZoneProviderShellHelper.assertNotCreated(); @@ -333,7 +383,8 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { testPrimaryLocationTimeZoneProviderPackageName, testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates */); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + // Turn on auto detection, which should activate the location time zone algorithm. + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); mPrimaryFakeTimeZoneProviderShellHelper.assertNotCreated(); mSecondaryFakeTimeZoneProviderShellHelper.assertCreated(); @@ -382,7 +433,8 @@ public class LocationTimeZoneManagerHostTest extends BaseHostJUnit4Test { testPrimaryLocationTimeZoneProviderPackageName, testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates*/); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + // Turn on auto detection, which should activate the location time zone algorithm. + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); mPrimaryFakeTimeZoneProviderShellHelper.assertCreated(); mSecondaryFakeTimeZoneProviderShellHelper.assertCreated(); diff --git a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerStatsTest.java b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerStatsTest.java index e591d2d1a9f..9ab524d9dc1 100644 --- a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerStatsTest.java +++ b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerStatsTest.java @@ -53,10 +53,15 @@ import java.util.List; import java.util.Set; import java.util.function.Function; -/** Host-side CTS tests for the location time zone manager service stats logging. */ +/** + * Host-side CTS tests for the location time zone manager service stats logging. Very similar to + * {@link LocationTimeZoneManagerHostTest} but focused on stats logging. + */ @RunWith(DeviceJUnit4ClassRunner.class) public class LocationTimeZoneManagerStatsTest extends BaseHostJUnit4Test { + private static final String NON_EXISTENT_TZPS_APP_PACKAGE = "foobar"; + private static final int PRIMARY_PROVIDER_INDEX = 0; private static final int SECONDARY_PROVIDER_INDEX = 1; @@ -80,8 +85,8 @@ public class LocationTimeZoneManagerStatsTest extends BaseHostJUnit4Test { mLocationTimeZoneManagerShellHelper = new LocationTimeZoneManagerShellHelper(shellCommandExecutor); - // Confirm the service being tested is present. It can be turned off, in which case there's - // nothing to test. + // Confirm the service being tested is present. It can be turned off permanently in config, + // in which case there's nothing about it to test. mLocationTimeZoneManagerShellHelper.assumeLocationTimeZoneManagerIsPresent(); // Install the app that hosts the fake providers. @@ -92,34 +97,57 @@ public class LocationTimeZoneManagerStatsTest extends BaseHostJUnit4Test { mLocationShellHelper = new LocationShellHelper(shellCommandExecutor); mDeviceConfigShellHelper = new DeviceConfigShellHelper(shellCommandExecutor); + // Stop device_config updates for the duration of the test. mDeviceConfigPreTestState = mDeviceConfigShellHelper.setSyncModeForTest( SYNC_DISABLED_MODE_UNTIL_REBOOT, NAMESPACE_SYSTEM_TIME); - // All tests start with the location_time_zone_manager disabled so that providers can be - // configured. + // These original values try to record the raw value of the settings before the test ran: + // they may be ignored by the location_time_zone_manager service when they have no meaning. + // Unfortunately, we cannot tell if the value returned is the result of setting defaults or + // real values, which means we may not return things exactly as they were. To do better + // would require looking at raw settings values and use internal knowledge of settings keys. + mOriginalAutoDetectionEnabled = mTimeZoneDetectorShellHelper.isAutoDetectionEnabled(); + mOriginalGeoDetectionEnabled = mTimeZoneDetectorShellHelper.isGeoDetectionEnabled(); + mLocationTimeZoneManagerShellHelper.stop(); - // Make sure locations is enabled, otherwise the geo detection feature will be disabled - // whatever the geolocation detection setting is set to. + // Make sure location is enabled, otherwise the geo detection feature cannot operate. mOriginalLocationEnabled = mLocationShellHelper.isLocationEnabledForCurrentUser(); if (!mOriginalLocationEnabled) { mLocationShellHelper.setLocationEnabledForCurrentUser(true); } - // Make sure automatic time zone detection is enabled, otherwise the geo detection feature - // will be disabled whatever the geolocation detection setting is set to - mOriginalAutoDetectionEnabled = mTimeZoneDetectorShellHelper.isAutoDetectionEnabled(); - if (!mOriginalAutoDetectionEnabled) { - mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); + // Restart the location_time_zone_manager with a do-nothing test config; some settings + // values cannot be set when the service knows that the settings won't be used. Devices + // can be encountered with the location_time_zone_manager enabled but with no providers + // installed. Starting the service with a valid-looking test provider config means we know + // settings changes will be accepted regardless of the real config. + String testPrimaryLocationTimeZoneProviderPackageName = NON_EXISTENT_TZPS_APP_PACKAGE; + String testSecondaryLocationTimeZoneProviderPackageName = null; + mLocationTimeZoneManagerShellHelper.startWithTestProviders( + testPrimaryLocationTimeZoneProviderPackageName, + testSecondaryLocationTimeZoneProviderPackageName, + false /* recordProviderStates */); + + // Begin all tests with auto detection turned off. + if (mOriginalAutoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(false); } - // On devices with no location time zone providers (e.g. AOSP), we cannot turn geo detection - // on until the test LTZPs are configured as the time_zone_detector will refuse. - mOriginalGeoDetectionEnabled = mTimeZoneDetectorShellHelper.isGeoDetectionEnabled(); + // We set the device settings so that location detection will be used. + if (!mOriginalGeoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + } - // Make sure that the fake providers used in the tests are available. + // All tests begin with the location_time_zone_manager stopped so that fake providers can be + // configured. + mLocationTimeZoneManagerShellHelper.stop(); + + // Make sure the fake provider APK install started above has completed before tests try to + // use the fake providers. FakeTimeZoneProviderAppShellHelper fakeTimeZoneProviderAppShellHelper = new FakeTimeZoneProviderAppShellHelper(shellCommandExecutor); + // Delay until the fake TZPS app can be found. fakeTimeZoneProviderAppShellHelper.waitForInstallation(); ConfigUtils.removeConfig(device); @@ -133,27 +161,36 @@ public class LocationTimeZoneManagerStatsTest extends BaseHostJUnit4Test { return; } - // Reset the geoDetectionEnabled state while there is at least one LTZP configured: this - // setting cannot be modified if there are no LTZPs on the device, e.g. on AOSP. - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(mOriginalGeoDetectionEnabled); - - // Turn off the service before we reset configuration, otherwise it will restart itself - // repeatedly. + // Restart the location_time_zone_manager with a test config so that the device can be set + // back to the starting state regardless of how the test left things. mLocationTimeZoneManagerShellHelper.stop(); + String testPrimaryLocationTimeZoneProviderPackageName = NON_EXISTENT_TZPS_APP_PACKAGE; + String testSecondaryLocationTimeZoneProviderPackageName = null; + mLocationTimeZoneManagerShellHelper.startWithTestProviders( + testPrimaryLocationTimeZoneProviderPackageName, + testSecondaryLocationTimeZoneProviderPackageName, + false /* recordProviderStates */); + + if (mTimeZoneDetectorShellHelper.isGeoDetectionEnabled() != mOriginalGeoDetectionEnabled) { + mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(mOriginalGeoDetectionEnabled); + } - // Reset settings and server flags as best we can. if (mTimeZoneDetectorShellHelper.isAutoDetectionEnabled() != mOriginalAutoDetectionEnabled) { mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(mOriginalAutoDetectionEnabled); } + + // Everything else can be reset without worrying about the providers. + mLocationTimeZoneManagerShellHelper.stop(); + mLocationShellHelper.setLocationEnabledForCurrentUser(mOriginalLocationEnabled); ConfigUtils.removeConfig(getDevice()); ReportUtils.clearReports(getDevice()); mDeviceConfigShellHelper.restoreDeviceConfigStateForTest(mDeviceConfigPreTestState); - // Attempt to start the service. It may not start if there are no providers configured, - // but that is ok. + // Attempt to start the service without test providers. It may not start if there are no + // providers configured, but that is ok. mLocationTimeZoneManagerShellHelper.start(); } @@ -169,12 +206,12 @@ public class LocationTimeZoneManagerStatsTest extends BaseHostJUnit4Test { testSecondaryLocationTimeZoneProviderPackageName, true /* recordProviderStates */); - // Turn geo detection on and off, twice. + // Turn the location detection algorithm on and off, twice. for (int i = 0; i < 2; i++) { Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true); + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(true); Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); - mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(false); + mTimeZoneDetectorShellHelper.setAutoDetectionEnabled(false); } // Sorted list of events in order in which they occurred. diff --git a/libs/midi/OWNERS b/libs/midi/OWNERS new file mode 100644 index 00000000000..0808c5acacc --- /dev/null +++ b/libs/midi/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 48436 +philburk@google.com +pmclean@google.com +robertwu@google.com diff --git a/libs/webkit-shared/src/android/webkit/cts/HttpHeader.aidl b/libs/webkit-shared/src/android/webkit/cts/HttpHeader.aidl new file mode 100644 index 00000000000..644be025b65 --- /dev/null +++ b/libs/webkit-shared/src/android/webkit/cts/HttpHeader.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit.cts; + +parcelable HttpHeader; diff --git a/libs/webkit-shared/src/android/webkit/cts/HttpHeader.java b/libs/webkit-shared/src/android/webkit/cts/HttpHeader.java new file mode 100644 index 00000000000..26e01543a41 --- /dev/null +++ b/libs/webkit-shared/src/android/webkit/cts/HttpHeader.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit.cts; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Pair; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class attempts to match the Apache HttpRequest as close as possible so that it can be used + * in place of it. The apache HttpRequest is not parcelable. + */ +public class HttpHeader implements Parcelable { + private final String mHeader; + private final String mValue; + + public static final Parcelable.Creator<HttpHeader> CREATOR = + new Parcelable.Creator<HttpHeader>() { + public HttpHeader createFromParcel(Parcel in) { + return new HttpHeader(in); + } + + public HttpHeader[] newArray(int size) { + return new HttpHeader[size]; + } + }; + + /** Create a new HttpHeader from a header name and value string. */ + public static HttpHeader create(String header, String value) { + return new HttpHeader(header, value); + } + + /** Convert a list of HttpHeaders to a List of pairs to be used with CtsTestServer. */ + public static List<Pair<String, String>> asPairList(List<HttpHeader> headers) { + List<Pair<String, String>> pairList = new ArrayList<>(); + if (headers != null) { + for (HttpHeader header : headers) { + pairList.add(header.getPair()); + } + } + return pairList; + } + + HttpHeader(Parcel in) { + // Note: This must be read in the same order we write + // to the parcel in {@link #wroteToParcel(Parcel out, int flags)}. + this(in.readString(), in.readString()); + } + + HttpHeader(String header, String value) { + mHeader = header; + mValue = value; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + // Note: This must be written in the same order we read + // from the parcel in {@link #HttpRequest(Parcel in)}. + out.writeString(mHeader); + out.writeString(mValue); + } + + @Override + public int describeContents() { + return 0; + } + + private Pair<String, String> getPair() { + return Pair.create(mHeader, mValue); + } +} diff --git a/libs/webkit-shared/src/android/webkit/cts/IWebServer.aidl b/libs/webkit-shared/src/android/webkit/cts/IWebServer.aidl index f74f935c31e..77cde38bf83 100644 --- a/libs/webkit-shared/src/android/webkit/cts/IWebServer.aidl +++ b/libs/webkit-shared/src/android/webkit/cts/IWebServer.aidl @@ -17,14 +17,24 @@ package android.webkit.cts; import android.webkit.cts.HttpRequest; +import android.webkit.cts.HttpHeader; + +import java.util.List; interface IWebServer { - void start(int sslMode, in @nullable byte[] acceptedIssuerDer); + void start(int sslMode, in @nullable byte[] acceptedIssuerDer, int keyResId, int certResId); void shutdown(); void resetRequestState(); + String setResponse( + String path, String responseString, in List<HttpHeader> responseHeaders); + + String getAbsoluteUrl(String path); + + String getUserAgentUrl(); + String getDelayedAssetUrl(String path); String getRedirectingAssetUrl(String path); @@ -35,7 +45,21 @@ interface IWebServer { String getBinaryUrl(String mimeType, int contentLength); + String getAppCacheUrl(); + + int getRequestCount(); + + int getRequestCountWithPath(String path); + boolean wasResourceRequested(String url); + HttpRequest getLastRequest(String path); + HttpRequest getLastAssetRequest(String url); + + String getCookieUrl(String path); + + String getSetCookieUrl(String path, String key, String value, String attributes); + + String getLinkedScriptUrl(String path, String url); }
\ No newline at end of file diff --git a/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java b/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java index 4852f5aa33d..c3ceaf8c84a 100644 --- a/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java +++ b/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java @@ -20,6 +20,9 @@ import android.os.RemoteException; import androidx.annotation.Nullable; +import java.util.Collections; +import java.util.List; + /** * This class serves as the public fronting API for tests to interact with the CtsTestServer. * @@ -34,15 +37,11 @@ public final class SharedSdkWebServer { mWebServer = webServer; } - /** Starts the web server. */ - public void start(@SslMode int sslMode) { - start(new Config().setSslMode(sslMode)); - } - - /** Starts the web server using the provided {@link Config}. */ - public void start(Config config) { + /** Starts the web server using the provided parameters}. */ + public void start(@SslMode int sslMode, @Nullable byte[] acceptedIssuerDer, + int keyResId, int certResId) { try { - mWebServer.start(config.mSslMode, config.mAcceptedIssuerDer); + mWebServer.start(sslMode, acceptedIssuerDer, keyResId, certResId); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -66,6 +65,42 @@ public final class SharedSdkWebServer { } } + /** + * Sets a response to be returned when a particular request path is passed in (with the option + * to specify additional headers). + */ + public String setResponse( + String path, String responseString, List<HttpHeader> responseHeaders) { + // We can't send a null value as a list + // so default to an empty list if null was provided. + if (responseHeaders == null) { + responseHeaders = Collections.emptyList(); + } + try { + return mWebServer.setResponse(path, responseString, responseHeaders); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Return the absolute URL that refers to a path. */ + public String getAbsoluteUrl(String path) { + try { + return mWebServer.getAbsoluteUrl(path); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Returns a url that will contain the user agent in the header and in the body. */ + public String getUserAgentUrl() { + try { + return mWebServer.getUserAgentUrl(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** Get a delayed assert url for an asset path. */ public String getDelayedAssetUrl(String path) { try { @@ -78,7 +113,7 @@ public final class SharedSdkWebServer { /** Get a url that will redirect for a path. */ public String getRedirectingAssetUrl(String path) { try { - return mWebServer.getAssetUrl(path); + return mWebServer.getRedirectingAssetUrl(path); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -111,6 +146,33 @@ public final class SharedSdkWebServer { } } + /** Returns the url to the app cache. */ + public String getAppCacheUrl() { + try { + return mWebServer.getAppCacheUrl(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Returns how many requests have been made. */ + public int getRequestCount() { + try { + return mWebServer.getRequestCount(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Returns the request count for a particular path */ + public int getRequestCount(String path) { + try { + return mWebServer.getRequestCountWithPath(path); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** Verify if a resource was requested. */ public boolean wasResourceRequested(String url) { try { @@ -121,6 +183,15 @@ public final class SharedSdkWebServer { } /** Retrieve the last request to be made on a url. */ + public HttpRequest getLastRequest(String path) { + try { + return mWebServer.getLastRequest(path); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + /** Retrieve the last request for an asset path to be made on a url. */ public HttpRequest getLastAssetRequest(String url) { try { return mWebServer.getLastAssetRequest(url); @@ -129,34 +200,33 @@ public final class SharedSdkWebServer { } } - /** Configuration options for starting a SharedSdkWebServer */ - public static class Config { - private @SslMode int mSslMode; - private @Nullable byte[] mAcceptedIssuerDer; - - public Config() { - mSslMode = SslMode.INSECURE; - mAcceptedIssuerDer = null; + /** Returns a url that will contain the path as a cookie. */ + public String getCookieUrl(String path) { + try { + return mWebServer.getCookieUrl(path); + } catch (RemoteException e) { + throw new RuntimeException(e); } + } - /** Set the server's SslMode */ - public Config setSslMode(@SslMode int sslMode) { - mSslMode = sslMode; - return this; + /** + * Returns a URL that attempts to set the cookie + * "key=value" with the given list of attributes when fetched. + */ + public String getSetCookieUrl(String path, String key, String value, String attributes) { + try { + return mWebServer.getSetCookieUrl(path, key, value, attributes); + } catch (RemoteException e) { + throw new RuntimeException(e); } + } - /** - * Configures the server's TrustManager to contain a given accepted issuer certificate - * (specified as DER bytes). - * - * Note that this does not enforce that certificates are issued from this issuer - as with - * the default CTS trust manager, all certificates are always considered valid. Supplying an - * acceptedIssuer merely affects the issuer DNs contained in the certificate request sent to - * the client in the TLS handshake. - */ - public Config setAcceptedIssuer(@Nullable byte[] acceptedIssuerDer) { - mAcceptedIssuerDer = acceptedIssuerDer; - return this; + /** Returns a URL for a page with a script tag where src equals the URL passed in. */ + public String getLinkedScriptUrl(String path, String url) { + try { + return mWebServer.getLinkedScriptUrl(path, url); + } catch (RemoteException e) { + throw new RuntimeException(e); } } } diff --git a/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java b/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java index c590e9c9686..eb43397fad6 100644 --- a/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java +++ b/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java @@ -19,6 +19,7 @@ package android.webkit.cts; import static org.junit.Assert.*; import android.app.Instrumentation; +import android.app.UiAutomation; import android.content.Context; import android.os.RemoteException; import android.os.StrictMode; @@ -39,6 +40,7 @@ import java.io.ByteArrayInputStream; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.List; import javax.net.ssl.X509TrustManager; @@ -131,6 +133,25 @@ public final class SharedWebViewTestEnvironment { } } + /** Returns a web server that has been started and can be used + * for web based testing. */ + public SharedSdkWebServer getSetupWebServer(@SslMode int sslMode) { + return getSetupWebServer(sslMode, null, 0, 0); + } + + /** Returns a web server that has been started and can be used + * for web based testing. */ + public SharedSdkWebServer getSetupWebServer(@SslMode int sslMode, + @Nullable byte[] acceptedIssuerDer, int keyResId, int certResId) { + try { + SharedSdkWebServer webServer = getWebServer(); + webServer.start(sslMode, acceptedIssuerDer, keyResId, certResId); + return webServer; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + /** * Use this builder to create a {@link SharedWebViewTestEnvironment}. The {@link * SharedWebViewTestEnvironment} can not be built directly. @@ -183,12 +204,27 @@ public final class SharedWebViewTestEnvironment { } /** + * UiAutomation sends events at device level which lets us get around issues with sending + * instrumented events to the SDK Runtime but we don't want this for the regular tests. If + * something like a dialog pops up while an input event is being sent, the instrumentation would + * treat that as an issue while the UiAutomation input event would just send it through. + * + * <p>So by default, we disable this use and only use it in the SDK Sandbox. + * + * <p>This API is used for regular activity based tests. + */ + public static IHostAppInvoker.Stub createHostAppInvoker(Context applicationContext) { + return createHostAppInvoker(applicationContext, false); + } + /** * This will generate a new {@link IHostAppInvoker} binder node. This should be called from * wherever the activity exists for test cases. */ - public static IHostAppInvoker.Stub createHostAppInvoker(Context applicationContext) { + public static IHostAppInvoker.Stub createHostAppInvoker( + Context applicationContext, boolean allowUiAutomation) { return new IHostAppInvoker.Stub() { private Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); + private UiAutomation mUiAutomation; public void waitForIdleSync() { mInstrumentation.waitForIdleSync(); @@ -199,7 +235,11 @@ public final class SharedWebViewTestEnvironment { } public void sendPointerSync(MotionEvent event) { - mInstrumentation.sendPointerSync(event); + if (allowUiAutomation) { + sendPointerSyncWithUiAutomation(event); + } else { + sendPointerSyncWithInstrumentation(event); + } } public byte[] getEncodingBytes(String data, String charset) { @@ -210,16 +250,21 @@ public final class SharedWebViewTestEnvironment { return new IWebServer.Stub() { private CtsTestServer mWebServer; - public void start(@SslMode int sslMode, @Nullable byte[] acceptedIssuerDer) { + public void start(@SslMode int sslMode, @Nullable byte[] acceptedIssuerDer, + int keyResId, int certResId) { assertNull(mWebServer); final X509Certificate[] acceptedIssuerCerts; if (acceptedIssuerDer != null) { try { - CertificateFactory certFactory = CertificateFactory.getInstance( - "X.509"); - acceptedIssuerCerts = new X509Certificate[]{ - (X509Certificate) certFactory.generateCertificate( - new ByteArrayInputStream(acceptedIssuerDer))}; + CertificateFactory certFactory = + CertificateFactory.getInstance("X.509"); + acceptedIssuerCerts = + new X509Certificate[] { + (X509Certificate) + certFactory.generateCertificate( + new ByteArrayInputStream( + acceptedIssuerDer)) + }; } catch (CertificateException e) { // Throw manually, because compiler does not understand that fail() // does not return. @@ -237,9 +282,9 @@ public final class SharedWebViewTestEnvironment { } }; mWebServer = new CtsTestServer(applicationContext, sslMode, - trustManager); + trustManager, keyResId, certResId); } catch (Exception e) { - fail("Failed to launch CtsTestServer"); + fail(" Failed to launch CtsTestServer: " + e); } } @@ -261,6 +306,23 @@ public final class SharedWebViewTestEnvironment { mWebServer.resetRequestState(); } + public String setResponse( + String path, String responseString, List<HttpHeader> responseHeaders) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.setResponse( + path, responseString, HttpHeader.asPairList(responseHeaders)); + } + + public String getAbsoluteUrl(String path) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getAbsoluteUrl(path); + } + + public String getUserAgentUrl() { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getUserAgentUrl(); + } + public String getDelayedAssetUrl(String path) { assertNotNull("The WebServer needs to be started", mWebServer); return mWebServer.getDelayedAssetUrl(path); @@ -286,22 +348,80 @@ public final class SharedWebViewTestEnvironment { return mWebServer.getBinaryUrl(mimeType, contentLength); } + public String getAppCacheUrl() { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getAppCacheUrl(); + } + + public int getRequestCount() { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getRequestCount(); + } + + public int getRequestCountWithPath(String path) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getRequestCount(path); + } + public boolean wasResourceRequested(String url) { assertNotNull("The WebServer needs to be started", mWebServer); return mWebServer.wasResourceRequested(url); } + public HttpRequest getLastRequest(String path) { + assertNotNull("The WebServer needs to be started", mWebServer); + return toHttpRequest(path, mWebServer.getLastRequest(path)); + } + public HttpRequest getLastAssetRequest(String url) { assertNotNull("The WebServer needs to be started", mWebServer); - org.apache.http.HttpRequest request = mWebServer.getLastAssetRequest(url); - if (request == null) { + return toHttpRequest(url, mWebServer.getLastAssetRequest(url)); + } + + public String getCookieUrl(String path) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getCookieUrl(path); + } + + public String getSetCookieUrl(String path, String key, String value, + String attributes) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getSetCookieUrl(path, key, value, attributes); + } + + public String getLinkedScriptUrl(String path, String url) { + assertNotNull("The WebServer needs to be started", mWebServer); + return mWebServer.getLinkedScriptUrl(path, url); + } + + private HttpRequest toHttpRequest( + String url, org.apache.http.HttpRequest apacheRequest) { + if (apacheRequest == null) { return null; } - return new HttpRequest(url, request); + return new HttpRequest(url, apacheRequest); } }; } + + private void sendPointerSyncWithInstrumentation(MotionEvent event) { + mInstrumentation.sendPointerSync(event); + } + + private void sendPointerSyncWithUiAutomation(MotionEvent event) { + if (mUiAutomation == null) { + mUiAutomation = mInstrumentation.getUiAutomation(); + + if (mUiAutomation == null) { + fail("Could not retrieve UI automation"); + } + } + + if (!mUiAutomation.injectInputEvent(event, true)) { + fail("Could not inject motion event"); + } + } }; } } diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java index c51ed92d40d..d19831751e0 100644 --- a/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java +++ b/tests/AlarmManager/src/android/alarmmanager/cts/BackgroundRestrictedAlarmsTest.java @@ -51,6 +51,7 @@ import com.android.compatibility.common.util.SystemUtil; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -155,6 +156,7 @@ public class BackgroundRestrictedAlarmsTest { + " times when restrictions were lifted", waitForAlarms(minCount, DEFAULT_WAIT)); } + @Ignore("Feature auto_restricted_bucket_on_bg_restricted is disabled right now") @Test public void testRepeatingAlarmAllowedWhenAutoRestrictedBucketFeatureOn() throws Exception { final long interval = MIN_REPEATING_INTERVAL; diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java index 1402975cfe6..6177592cde3 100644 --- a/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java +++ b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java @@ -16,6 +16,7 @@ package android.jobscheduler.cts; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -193,7 +194,9 @@ public class NetworkingHelper { } final NetworkCapabilities networkCapabilities = mConnectivityManager.getNetworkCapabilities(network); - return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI); + return networkCapabilities != null + && networkCapabilities.hasTransport(TRANSPORT_WIFI) + && networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED); } boolean isWifiEnabled() { @@ -300,6 +303,7 @@ public class NetworkingHelper { NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCapabilities nc = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_VALIDATED) .build(); NetworkTracker tracker = new NetworkTracker(nc, enable, mConnectivityManager); mConnectivityManager.registerNetworkCallback(nr, tracker); diff --git a/tests/PhotoPicker/res/raw/lg_g4_iso_800_svg.svg b/tests/PhotoPicker/res/raw/lg_g4_iso_800_svg.svg Binary files differnew file mode 100644 index 00000000000..55b3d2e8874 --- /dev/null +++ b/tests/PhotoPicker/res/raw/lg_g4_iso_800_svg.svg diff --git a/tests/PhotoPicker/res/raw/lg_g4_iso_800_unknown_mime_type.jpg b/tests/PhotoPicker/res/raw/lg_g4_iso_800_unknown_mime_type.jpg Binary files differnew file mode 100644 index 00000000000..c988c573fab --- /dev/null +++ b/tests/PhotoPicker/res/raw/lg_g4_iso_800_unknown_mime_type.jpg diff --git a/tests/PhotoPicker/res/raw/test_video_dng.mp4 b/tests/PhotoPicker/res/raw/test_video_mj2.mp4 Binary files differindex 9b38f0e8e7d..2b7decd215b 100644 --- a/tests/PhotoPicker/res/raw/test_video_dng.mp4 +++ b/tests/PhotoPicker/res/raw/test_video_mj2.mp4 diff --git a/tests/PhotoPicker/res/raw/test_video_mpeg.mpeg b/tests/PhotoPicker/res/raw/test_video_mpeg.mpeg Binary files differnew file mode 100644 index 00000000000..27b288ed028 --- /dev/null +++ b/tests/PhotoPicker/res/raw/test_video_mpeg.mpeg diff --git a/tests/PhotoPicker/res/raw/test_video_unknown_mime_type.mp4 b/tests/PhotoPicker/res/raw/test_video_unknown_mime_type.mp4 Binary files differnew file mode 100644 index 00000000000..5a2e7b56d00 --- /dev/null +++ b/tests/PhotoPicker/res/raw/test_video_unknown_mime_type.mp4 diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java index d0715e3f699..f818c10baaf 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java @@ -17,8 +17,11 @@ package android.photopicker.cts; import static android.photopicker.cts.util.PhotoPickerUiUtils.isPhotoPickerVisible; -import static android.photopicker.cts.util.PhotoPickerUiUtils.verifyActionBarExists; +import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActionBarIsVisible; import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActivityIsVisible; +import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsDescriptionIsVisible; +import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsFragmentContainerExists; +import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsTitleIsVisible; import android.content.Intent; import android.os.Build; @@ -91,7 +94,10 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest { // Verify PhotoPickerSettingsActivity is launched and visible. verifySettingsActivityIsVisible(sDevice); - verifyActionBarExists(); + verifySettingsActionBarIsVisible(); + verifySettingsTitleIsVisible(); + verifySettingsDescriptionIsVisible(); + verifySettingsFragmentContainerExists(); } private static String getAllowedProvidersDeviceConfig() throws IOException { diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java index 11d99d1ed41..293cbacd05c 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java @@ -18,8 +18,12 @@ package android.photopicker.cts; import static android.photopicker.cts.util.GetContentActivityAliasUtils.clearPackageData; import static android.photopicker.cts.util.GetContentActivityAliasUtils.getDocumentsUiPackageName; -import static android.photopicker.cts.util.PhotoPickerFilesUtils.createDNGVideosAndGetUris; +import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImageWithUnknownMimeType; import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUris; +import static android.photopicker.cts.util.PhotoPickerFilesUtils.createMj2VideosAndGetUris; +import static android.photopicker.cts.util.PhotoPickerFilesUtils.createMpegVideo; +import static android.photopicker.cts.util.PhotoPickerFilesUtils.createSvgImage; +import static android.photopicker.cts.util.PhotoPickerFilesUtils.createVideoWithUnknownMimeType; import static android.photopicker.cts.util.PhotoPickerFilesUtils.createVideosAndGetUris; import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia; import static android.photopicker.cts.util.PhotoPickerUiUtils.REGEX_PACKAGE_NAME; @@ -30,6 +34,7 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList; import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddButton; import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddOrSelectButton; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertContainsMimeType; +import static android.photopicker.cts.util.ResultsAssertionsUtils.assertExtension; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertMimeType; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPersistedGrant; import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat; @@ -63,6 +68,7 @@ import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; /** * Photo Picker Device only tests for common flows. @@ -229,7 +235,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { @Test public void testMultiSelect_longPress() throws Exception { final int videoCount = 3; - mUriList.addAll(createDNGVideosAndGetUris(videoCount, mContext.getUserId())); + mUriList.addAll(createMj2VideosAndGetUris(videoCount, mContext.getUserId())); Intent intent = new Intent(mAction); intent.setType("video/*"); @@ -544,11 +550,11 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { @Test public void testMimeTypeFilter() throws Exception { final int videoCount = 2; - mUriList.addAll(createDNGVideosAndGetUris(videoCount, mContext.getUserId())); + mUriList.addAll(createMj2VideosAndGetUris(videoCount, mContext.getUserId())); final int imageCount = 1; mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId())); - final String mimeType = "video/dng"; + final String mimeType = "video/mj2"; Intent intent = new Intent(mAction); addMultipleSelectionFlag(intent); @@ -579,9 +585,9 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { @Test public void testExtraMimeTypeFilter() throws Exception { - final int dngVideoCount = 2; - // Creates 2 videos with mime type: "video/dng" - mUriList.addAll(createDNGVideosAndGetUris(dngVideoCount, mContext.getUserId())); + final int mj2VideoCount = 2; + // Creates 2 videos with mime type: "video/mj2" + mUriList.addAll(createMj2VideosAndGetUris(mj2VideoCount, mContext.getUserId())); final int mp4VideoCount = 3; // Creates 3 videos with mime type: "video/mp4" @@ -597,11 +603,11 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { if (Intent.ACTION_GET_CONTENT.equals(intent.getAction())) { intent.setType("*/*"); } - final String[] mimeTypes = new String[]{"video/dng", "image/dng"}; + final String[] mimeTypes = new String[]{"video/mj2", "image/dng"}; intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes); launchPhotoPickerForIntent(intent); - final int totalCount = dngVideoCount + imageCount; + final int totalCount = mj2VideoCount + imageCount; final List<UiObject> itemList = findItemList(totalCount); final int itemCount = itemList.size(); assertThat(itemCount).isAtLeast(totalCount); @@ -626,7 +632,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { @Test public void testMimeTypeFilterPriority() throws Exception { final int videoCount = 2; - mUriList.addAll(createDNGVideosAndGetUris(videoCount, mContext.getUserId())); + mUriList.addAll(createMj2VideosAndGetUris(videoCount, mContext.getUserId())); final int imageCount = 1; mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId())); @@ -634,7 +640,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { addMultipleSelectionFlag(intent); // setType has lower priority than EXTRA_MIME_TYPES filters. intent.setType("image/*"); - final String mimeType = "video/dng"; + final String mimeType = "video/mj2"; intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {mimeType}); launchPhotoPickerForIntent(intent); @@ -660,6 +666,53 @@ public class PhotoPickerTest extends PhotoPickerBaseTest { } } + @Test + public void testPickerUriFileExtensions() throws Exception { + // 1. Create test media items + mUriList.add(createSvgImage(mContext.getUserId())); + mUriList.add(createImageWithUnknownMimeType(mContext.getUserId())); + mUriList.add(createMpegVideo(mContext.getUserId())); + mUriList.add(createVideoWithUnknownMimeType(mContext.getUserId())); + + final int expectedItemCount = mUriList.size(); + + final Map<String, String> mimeTypeToExpectedExtensionMap = Map.of( + "image/svg+xml", "svg", + "image/foo", "jpg", + "video/mpeg", "mpeg", + "video/foo", "mp4" + ); + + // 2. Launch Picker in multi-select mode for the test mime types + final Intent intent = new Intent(mAction); + addMultipleSelectionFlag(intent); + launchPhotoPickerForIntent(intent); + + // 3. Add all items + final List<UiObject> itemList = findItemList(expectedItemCount); + final int itemCount = itemList.size(); + assertWithMessage("Unexpected number of media items found in the picker ui") + .that(itemCount) + .isEqualTo(expectedItemCount); + + for (UiObject item : itemList) { + clickAndWait(sDevice, item); + } + clickAndWait(sDevice, findAddButton()); + + // 4. Get the activity result data to extract the picker uris + final ClipData clipData = mActivity.getResult().data.getClipData(); + assertWithMessage("Unexpected number of items returned from the picker activity") + .that(clipData.getItemCount()) + .isEqualTo(itemCount); + + // 5. Assert the picker uri file extension as expected for each item + for (int i = 0; i < itemCount; i++) { + final Uri uri = clipData.getItemAt(i).getUri(); + assertExtension(uri, mimeTypeToExpectedExtensionMap); + } + } + private void assertMuteButtonState(UiObject muteButton, boolean isMuted) throws UiObjectNotFoundException { // We use content description to assert the state of the mute button, there is no other way diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java index 2732df71762..9a39a4006cc 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerFilesUtils.java @@ -28,6 +28,7 @@ import android.provider.cts.ProviderTestUtils; import android.provider.cts.media.MediaStoreUtils; import android.util.Pair; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import com.android.compatibility.common.util.ShellUtils; @@ -91,10 +92,10 @@ public class PhotoPickerFilesUtils { MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId, isFavorite); } - public static List<Uri> createDNGVideosAndGetUris(int count, int userId) throws Exception { + public static List<Uri> createMj2VideosAndGetUris(int count, int userId) throws Exception { List<Uri> uriList = new ArrayList<>(); for (int i = 0; i < count; i++) { - final Uri uri = createDNGVideo(userId); + final Uri uri = createMj2Video(userId); uriList.add(uri); clearMediaOwner(uri, userId); } @@ -131,8 +132,8 @@ public class PhotoPickerFilesUtils { ShellUtils.runShellCommand(cmd); } - private static Uri createDNGVideo(int userId) throws Exception { - return getPermissionAndStageMedia(R.raw.test_video_dng, + private static Uri createMj2Video(int userId) throws Exception { + return getPermissionAndStageMedia(R.raw.test_video_mj2, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId, /* isFavorite */ false).first; } @@ -176,4 +177,32 @@ public class PhotoPickerFilesUtils { return new Pair(session.publish(), displayName); } } + + @NonNull + public static Uri createSvgImage(int userId) throws Exception { + return getPermissionAndStageMedia(R.raw.lg_g4_iso_800_svg, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/svg+xml", userId, + /* isFavorite */ false).first; + } + + @NonNull + public static Uri createImageWithUnknownMimeType(int userId) throws Exception { + return getPermissionAndStageMedia(R.raw.lg_g4_iso_800_unknown_mime_type, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId, + /* isFavorite */ false).first; + } + + @NonNull + public static Uri createMpegVideo(int userId) throws Exception { + return getPermissionAndStageMedia(R.raw.test_video_mpeg, + MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mpeg", userId, + /* isFavorite */ false).first; + } + + @NonNull + public static Uri createVideoWithUnknownMimeType(int userId) throws Exception { + return getPermissionAndStageMedia(R.raw.test_video_unknown_mime_type, + MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId, + /* isFavorite */ false).first; + } } diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java index 49a4eb40e1a..85b0e89fefd 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java @@ -119,10 +119,34 @@ public class PhotoPickerUiUtils { PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/bottom_sheet")).waitForExists(TIMEOUT); } - public static void verifyActionBarExists() { + public static void verifySettingsActionBarIsVisible() { assertWithMessage("Timed out waiting for action bar to appear") .that(new UiObject(new UiSelector() - .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/action_bar")) + .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_toolbar")) + .waitForExists(TIMEOUT)) + .isTrue(); + } + + public static void verifySettingsTitleIsVisible() { + assertWithMessage("Timed out waiting for settings page title to appear") + .that(new UiObject(new UiSelector() + .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_title")) + .waitForExists(TIMEOUT)) + .isTrue(); + } + + public static void verifySettingsDescriptionIsVisible() { + assertWithMessage("Timed out waiting for settings page description to appear") + .that(new UiObject(new UiSelector() + .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/picker_settings_description")) + .waitForExists(TIMEOUT)) + .isTrue(); + } + + public static void verifySettingsFragmentContainerExists() { + assertWithMessage("Timed out waiting for settings fragment container to appear") + .that(new UiObject(new UiSelector() + .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/settings_fragment_container")) .waitForExists(TIMEOUT)) .isTrue(); } diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java index e08dd2a1e2e..2f346770215 100644 --- a/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java +++ b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java @@ -33,6 +33,7 @@ import android.net.Uri; import android.os.FileUtils; import android.os.ParcelFileDescriptor; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import java.io.ByteArrayOutputStream; @@ -44,6 +45,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; /** * Photo Picker Utility methods for PhotoPicker result assertions. @@ -107,11 +109,39 @@ public class ResultsAssertionsUtils { } } + public static void assertExtension(@NonNull Uri uri, + @NonNull Map<String, String> mimeTypeToExpectedExtensionMap) { + assertThat(uri).isNotNull(); + + final ContentResolver resolver = + InstrumentationRegistry.getTargetContext().getContentResolver(); + final String[] projection = + new String[]{ PickerMediaColumns.MIME_TYPE, PickerMediaColumns.DISPLAY_NAME }; + + try (Cursor c = resolver.query( + uri, projection, /* queryArgs */ null, /* cancellationSignal */ null)) { + assertThat(c).isNotNull(); + assertThat(c.moveToFirst()).isTrue(); + + final String mimeType = c.getString(c.getColumnIndex(PickerMediaColumns.MIME_TYPE)); + final String expectedExtension = mimeTypeToExpectedExtensionMap.get(mimeType); + + final String displayName = + c.getString(c.getColumnIndex(PickerMediaColumns.DISPLAY_NAME)); + final String[] displayNameParts = displayName.split("\\."); + final String resultExtension = displayNameParts[displayNameParts.length - 1]; + + assertWithMessage("Unexpected picker file extension") + .that(resultExtension) + .isEqualTo(expectedExtension); + } + } + private static void assertVideoRedactedReadOnlyAccess(Uri uri, ContentResolver resolver) throws Exception { // The location is redacted // TODO(b/201505595): Make this method work for test_video.mp4. Currently it works only for - // test_video_dng.mp4 + // test_video_mj2.mp4 try (InputStream in = resolver.openInputStream(uri); ByteArrayOutputStream out = new ByteArrayOutputStream()) { FileUtils.copy(in, out); diff --git a/tests/accessibilityservice/res/layout/accessibility_cache.xml b/tests/accessibilityservice/res/layout/accessibility_cache.xml index 0a7839c72b0..2bfd467c0d0 100644 --- a/tests/accessibilityservice/res/layout/accessibility_cache.xml +++ b/tests/accessibilityservice/res/layout/accessibility_cache.xml @@ -21,11 +21,15 @@ android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout + android:focusable="true" + android:id="@+id/subtreeRoot" + android:contentDescription="Subtree root" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <TextView + android:contentDescription="Text view" android:text="textView" android:layout_width="60dp" android:layout_height="60dp" @@ -33,12 +37,12 @@ <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:contentDescription="child layout" - + android:contentDescription="Child layout" android:gravity="center" android:orientation="horizontal"> <TextView android:id="@+id/text" + android:contentDescription="Text view 2" android:text="textView2" android:layout_width="60dp" android:layout_height="60dp" diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityCacheTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityCacheTest.java index 89a874ec21f..c8ef56e6392 100644 --- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityCacheTest.java +++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityCacheTest.java @@ -20,7 +20,6 @@ import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchA import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; @@ -50,6 +49,7 @@ import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.runner.RunWith; +import java.util.ArrayList; import java.util.List; @AppModeFull @@ -71,6 +71,8 @@ public class AccessibilityCacheTest { mInstrumentedAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>( InstrumentedAccessibilityService.class, false); + private static final String SUBTREE_ROOT_ID = "android.accessibilityservice.cts:id/subtreeRoot"; + @Rule public final RuleChain mRuleChain = RuleChain .outerRule(mActivityRule) @@ -128,9 +130,10 @@ public class AccessibilityCacheTest { @Test public void invalidateNode_subtreeInCacheInvalidated() { - // Tree is FrameLayout with TextView and LinearLayout children. + // Subtree is FrameLayout with TextView and LinearLayout children. // The LinearLayout has a TextView child. - AccessibilityNodeInfo root = mService.getRootInActiveWindow(); + AccessibilityNodeInfo root = mService.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(SUBTREE_ROOT_ID).get(0); assertThat(root.getChildCount(), is(2)); AccessibilityNodeInfo child0 = root.getChild(0); AccessibilityNodeInfo child1 = root.getChild(1); @@ -146,27 +149,26 @@ public class AccessibilityCacheTest { @Test public void clear_cacheInvalidated() { - // Tree is FrameLayout with TextView and LinearLayout children. - // The LinearLayout has a TextView child. AccessibilityNodeInfo root = mService.getRootInActiveWindow(); - assertThat(root.getChildCount(), is(2)); - AccessibilityNodeInfo child0 = root.getChild(0); - AccessibilityNodeInfo child1 = root.getChild(1); - AccessibilityNodeInfo grandChild = child1.getChild(0); + + List<AccessibilityNodeInfo> allNodes = new ArrayList<>(); + allNodes.add(root); + getNodes(allNodes, root); assertTrue(mService.clearCache()); - assertFalse("Root is in cache", mService.isNodeInCache(root)); - assertFalse("Child0 is in cache", mService.isNodeInCache(child0)); - assertFalse("Child1 is in cache", mService.isNodeInCache(child1)); - assertFalse("Grandchild is in cache", mService.isNodeInCache(grandChild)); + for (AccessibilityNodeInfo node : allNodes) { + assertFalse("Node " + node.getContentDescription() + " is in cache", + mService.isNodeInCache(node)); + } } @Test public void getChild_descendantNotPrefetched() { - // Tree is FrameLayout with TextView and LinearLayout children. + // Subtree is FrameLayout with TextView and LinearLayout children. // The LinearLayout has a TextView child. - AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow(); + AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(SUBTREE_ROOT_ID).get(0); assertThat(frameRoot.getChildCount(), is(2)); AccessibilityNodeInfo textViewChild = frameRoot.getChild(0); AccessibilityNodeInfo linearLayoutChild = frameRoot.getChild(1); @@ -185,9 +187,10 @@ public class AccessibilityCacheTest { @Test public void getChild_descendantPrefetched() { - // Tree is FrameLayout with TextView and LinearLayout children. + // Subtree is FrameLayout with TextView and LinearLayout children. // The LinearLayout has a TextView child. - AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow(); + AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(SUBTREE_ROOT_ID).get(0); assertThat(frameRoot.getChildCount(), is(2)); AccessibilityNodeInfo textViewChild = frameRoot.getChild(0); AccessibilityNodeInfo linearLayoutChild = frameRoot.getChild(1); @@ -208,9 +211,10 @@ public class AccessibilityCacheTest { @Test public void getParent_ancestorsPrefetched() { - // Tree is FrameLayout with TextView and LinearLayout children. + // Subtree is FrameLayout with TextView and LinearLayout children. // The LinearLayout has a TextView child. - AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow(); + AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(SUBTREE_ROOT_ID).get(0); assertThat(frameRoot.getChildCount(), is(2)); AccessibilityNodeInfo textViewChild = frameRoot.getChild(0); AccessibilityNodeInfo linearLayoutChild = frameRoot.getChild(1); @@ -235,9 +239,10 @@ public class AccessibilityCacheTest { */ @Test public void testRequest_withMultiplePrefetchingStrategies_throwsException() { - // Tree is FrameLayout with TextView and LinearLayout children. + // Subtree is FrameLayout with TextView and LinearLayout children. // The LinearLayout has a TextView child. - AccessibilityNodeInfo root = mService.getRootInActiveWindow(); + AccessibilityNodeInfo root = mService.getRootInActiveWindow() + .findAccessibilityNodeInfosByViewId(SUBTREE_ROOT_ID).get(0); assertThat(root.getChildCount(), is(2)); // Clear cache. @@ -264,46 +269,47 @@ public class AccessibilityCacheTest { assertNotNull(activityWindowInfo); AccessibilityNodeInfo windowRoot = activityWindowInfo.getRoot(); - assertThat(windowRoot.getChildCount(), is(2)); - AccessibilityNodeInfo textViewChild = windowRoot.getChild(0); - AccessibilityNodeInfo linearLayoutChild = windowRoot.getChild(1); - AccessibilityNodeInfo frameGrandChild = linearLayoutChild.getChild(0); + List<AccessibilityNodeInfo> allNodes = new ArrayList<>(); + allNodes.add(windowRoot); // root should not be in the cache after clearing + getNodes(allNodes, windowRoot); // Clear cache. assertTrue(mService.clearCachedSubtree(windowRoot)); - AccessibilityNodeInfo windowRoot2 = activityWindowInfo.getRoot( - AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS - | AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE); - // Confirm roots are the same. - assertEquals(windowRoot, windowRoot2); - assertFalse("Root is in cache", mService.isNodeInCache(windowRoot)); - assertFalse("TextView is in cache", mService.isNodeInCache(textViewChild)); - assertFalse("LinearLayout is in cache", mService.isNodeInCache(linearLayoutChild)); - assertFalse("Root grandchild is in cache", mService.isNodeInCache(frameGrandChild)); + for (AccessibilityNodeInfo node : allNodes) { + assertFalse("Node " + node.getContentDescription() + " is in cache", + mService.isNodeInCache(node)); + } } @Test public void testRequest_prefetchWithRootInActiveWindow() { - // Tree is FrameLayout with TextView and LinearLayout children. - // The LinearLayout has a TextView child. - AccessibilityNodeInfo frameRoot = mService.getRootInActiveWindow(); - assertThat(frameRoot.getChildCount(), is(2)); - AccessibilityNodeInfo textViewChild = frameRoot.getChild(0); - AccessibilityNodeInfo linearLayoutChild = frameRoot.getChild(1); - AccessibilityNodeInfo frameGrandChild = linearLayoutChild.getChild(0); + AccessibilityNodeInfo windowRoot = mService.getRootInActiveWindow(); + + List<AccessibilityNodeInfo> allNodesExceptRoot = new ArrayList<>(); + getNodes(allNodesExceptRoot, windowRoot); // Clear cache. - assertTrue(mService.clearCachedSubtree(frameRoot)); + assertTrue(mService.clearCachedSubtree(windowRoot)); - AccessibilityNodeInfo frameRoot2 = mService.getRootInActiveWindow( + AccessibilityNodeInfo windowRoot2 = mService.getRootInActiveWindow( AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS | AccessibilityNodeInfo.FLAG_PREFETCH_UNINTERRUPTIBLE); - // Confirm roots are the same. - assertEquals(frameRoot, frameRoot2); - assertTrue("Root is in cache", mService.isNodeInCache(frameRoot2)); - assertFalse("TextView is in cache", mService.isNodeInCache(textViewChild)); - assertFalse("LinearLayout is in cache", mService.isNodeInCache(linearLayoutChild)); - assertFalse("Root grandchild is in cache", mService.isNodeInCache(frameGrandChild)); + + assertTrue("Root is in cache", mService.isNodeInCache(windowRoot2)); + for (AccessibilityNodeInfo node : allNodesExceptRoot) { + assertFalse("Node " + node.getContentDescription() + " is in cache", + mService.isNodeInCache(node)); + } + } + + private void getNodes(List<AccessibilityNodeInfo> nodesList, AccessibilityNodeInfo node) { + // Explicitly not prefetching to avoid a race condition where the cache may be populated + // after calling clearCachedSubtree + final int noPrefetchingStrategy = 0; + for (int i = 0; i < node.getChildCount(); i++) { + nodesList.add(node.getChild(i, noPrefetchingStrategy)); + getNodes(nodesList, node.getChild(i)); + } } } diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java index 01d1659f95b..7312c26da0a 100644 --- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java +++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityServiceInfoTest.java @@ -16,18 +16,26 @@ package android.accessibilityservice.cts; +import static android.accessibilityservice.cts.utils.CtsTestUtils.assertThrows; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import android.accessibility.cts.common.AccessibilityDumpOnFailureRule; +import android.accessibility.cts.common.InstrumentedAccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.os.Parcel; +import android.platform.test.annotations.AsbSecurityTest; import android.platform.test.annotations.Presubmit; import android.view.accessibility.AccessibilityEvent; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import com.google.common.base.Strings; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,7 +45,7 @@ import org.junit.runner.RunWith; */ @Presubmit @RunWith(AndroidJUnit4.class) -public class AccessibilityServiceInfoTest { +public class AccessibilityServiceInfoTest extends StsExtraBusinessLogicTestCase { @Rule public final AccessibilityDumpOnFailureRule mDumpOnFailureRule = @@ -131,6 +139,22 @@ public class AccessibilityServiceInfoTest { } + @Test + @AsbSecurityTest(cveBugId = {261589597}) + public void testSetServiceInfo_throwsForLargeServiceInfo() { + try { + final InstrumentedAccessibilityService service = + InstrumentedAccessibilityService.enableService( + InstrumentedAccessibilityService.class); + final AccessibilityServiceInfo info = service.getServiceInfo(); + info.packageNames = new String[]{Strings.repeat("A", 1024 * 507)}; + + assertThrows(IllegalStateException.class, () -> service.setServiceInfo(info)); + } finally { + InstrumentedAccessibilityService.disableAllServices(); + } + } + /** * Fully populates the {@link AccessibilityServiceInfo} to marshal. * diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java index 26ab62bb330..d5cfb39410d 100644 --- a/tests/app/app/src/android/app/stubs/CommandReceiver.java +++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java @@ -464,7 +464,9 @@ public class CommandReceiver extends BroadcastReceiver { private static Intent makeIntent(int command, String sourcePackage, String targetPackage, int flags, Bundle extras) { Intent intent = new Intent(); - if (command == COMMAND_BIND_SERVICE || command == COMMAND_START_FOREGROUND_SERVICE) { + if (command == COMMAND_BIND_SERVICE || command == COMMAND_START_FOREGROUND_SERVICE + || command == COMMAND_STOP_FOREGROUND_SERVICE || command == COMMAND_START_ACTIVITY + || command == COMMAND_START_FOREGROUND_SERVICE_LOCATION || command == COMMAND_UNBIND_SERVICE) { intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); } intent.setComponent(new ComponentName(sourcePackage, "android.app.stubs.CommandReceiver")); diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml index 22c253102a1..71a0925dd19 100644 --- a/tests/backup/AndroidManifest.xml +++ b/tests/backup/AndroidManifest.xml @@ -19,6 +19,8 @@ package="android.backup.cts"> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <application> <uses-library android:name="android.test.runner" /> <uses-library android:name="org.apache.http.legacy" /> diff --git a/tests/backup/src/android/backup/cts/AppLocalesBackupTest.java b/tests/backup/src/android/backup/cts/AppLocalesBackupTest.java index aab41595553..d51b7ae0af5 100644 --- a/tests/backup/src/android/backup/cts/AppLocalesBackupTest.java +++ b/tests/backup/src/android/backup/cts/AppLocalesBackupTest.java @@ -23,7 +23,6 @@ import static com.android.compatibility.common.util.SystemUtil.callWithShellPerm import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import android.Manifest; -import android.app.Instrumentation; import android.app.LocaleManager; import android.app.time.ExternalTimeSuggestion; import android.app.time.TimeManager; @@ -38,6 +37,7 @@ import android.content.IntentFilter; import android.os.LocaleList; import android.os.SystemClock; import android.platform.test.annotations.AppModeFull; +import android.provider.Settings; import androidx.test.InstrumentationRegistry; @@ -72,8 +72,13 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { private static final Duration RETENTION_PERIOD = Duration.ofDays(3); + private static final String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = + "cmd time_detector is_auto_detection_enabled"; + private Context mContext; private LocaleManager mLocaleManager; + private boolean mOriginalAutoTime; + private DeviceShellCommandExecutor mShellCommandExecutor; @Before @Override @@ -82,6 +87,14 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { mContext = InstrumentationRegistry.getTargetContext(); mLocaleManager = mContext.getSystemService(LocaleManager.class); + mShellCommandExecutor = new InstrumentationShellCommandExecutor( + InstrumentationRegistry.getInstrumentation().getUiAutomation()); + + mOriginalAutoTime = isAutoDetectionEnabled(mShellCommandExecutor); + // Auto time needs to be enabled to be able to suggest external time + if (!mOriginalAutoTime) { + assertTrue(setAutoTimeEnabled(/*enabled*/ true, mShellCommandExecutor)); + } install(TEST_APP_APK_1); install(TEST_APP_APK_2); @@ -89,6 +102,11 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { @After public void tearDown() throws Exception { + // reset auto time to its original value + if (!mOriginalAutoTime) { + setAutoTimeEnabled(/*enabled*/ false, mShellCommandExecutor); + } + uninstall(TEST_APP_PACKAGE_1); uninstall(TEST_APP_PACKAGE_2); } @@ -239,11 +257,8 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { // Locales for App1 should be restored immediately since that's present already. assertLocalesForApp(TEST_APP_PACKAGE_1, DEFAULT_LOCALES_1); - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - DeviceShellCommandExecutor shellCommandExecutor = new InstrumentationShellCommandExecutor( - instrumentation.getUiAutomation()); DeviceConfigShellHelper deviceConfigShellHelper = new DeviceConfigShellHelper( - shellCommandExecutor); + mShellCommandExecutor); // This anticipates a future state where a generally applied target preparer may disable // device_config sync for all CTS tests: only suspend syncing if it isn't already suspended, @@ -337,11 +352,9 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { getBackupUtils().restoreAndAssertSuccess(RESTORE_TOKEN, SYSTEM_PACKAGE); - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - DeviceShellCommandExecutor shellCommandExecutor = new InstrumentationShellCommandExecutor( - instrumentation.getUiAutomation()); + DeviceConfigShellHelper deviceConfigShellHelper = new DeviceConfigShellHelper( - shellCommandExecutor); + mShellCommandExecutor); // This anticipates a future state where a generally applied target preparer may disable // device_config sync for all CTS tests: only suspend syncing if it isn't already suspended, @@ -482,6 +495,23 @@ public class AppLocalesBackupTest extends BaseBackupCtsTest { setApplicationLocalesAndVerify(TEST_APP_PACKAGE_2, EMPTY_LOCALES); } + private boolean isAutoDetectionEnabled( + DeviceShellCommandExecutor shellCommandExecutor) throws Exception { + return shellCommandExecutor.executeToBoolean(SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED); + } + + private boolean setAutoTimeEnabled( + boolean enabled, DeviceShellCommandExecutor shellCommandExecutor) throws Exception { + // Android T does not have a dedicated shell command or API to change time auto detection + // setting, so direct Settings changes are used. + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME, + enabled ? 1 : 0); + + sleepForAsyncOperation(); + + return isAutoDetectionEnabled(shellCommandExecutor) == enabled; + } + private static final class BlockingBroadcastReceiver extends BroadcastReceiver { private CountDownLatch mLatch = new CountDownLatch(1); private String mPackageName; 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 772e7a599cb..7e88b27b560 100644 --- a/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java +++ b/tests/camera/api31test/src/android/camera/cts/api31test/SPerfClassTest.java @@ -125,9 +125,8 @@ public class SPerfClassTest extends AndroidTestCase { for (Size jpegSize : jpegSizes) { mCollector.expectTrue( "Primary camera's JPEG size must be at least 1080p, but is " + - jpegSize, - jpegSize.getWidth() >= FULLHD.getWidth() && - jpegSize.getHeight() >= FULLHD.getHeight()); + jpegSize, jpegSize.getWidth() * jpegSize.getHeight() + >= FULLHD.getWidth() * FULLHD.getHeight()); } CameraDevice camera = null; diff --git a/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java index 35edd778854..e7cb07a5698 100644 --- a/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/MultiResolutionImageReaderTest.java @@ -18,8 +18,8 @@ package android.hardware.camera2.cts; import android.graphics.ImageFormat; import android.hardware.HardwareBuffer; -import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; @@ -28,41 +28,37 @@ import android.hardware.camera2.MultiResolutionImageReader; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.cts.CameraTestUtils.HandlerExecutor; import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; -import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; import android.hardware.camera2.cts.helpers.StaticMetadata; +import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; import android.hardware.camera2.params.MandatoryStreamCombination; -import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap; import android.hardware.camera2.params.MultiResolutionStreamInfo; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; -import android.media.ImageReader; import android.util.Log; -import android.util.Range; import android.util.Size; import android.view.Surface; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; -import java.util.concurrent.LinkedBlockingQueue; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.junit.Test; -import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationSupported; import static android.hardware.camera2.cts.CameraTestUtils.ImageAndMultiResStreamInfo; -import static android.hardware.camera2.cts.CameraTestUtils.StreamCombinationTargets; import static android.hardware.camera2.cts.CameraTestUtils.SimpleMultiResolutionImageReaderListener; +import static android.hardware.camera2.cts.CameraTestUtils.StreamCombinationTargets; +import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationSupported; + import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; + import static org.mockito.Mockito.*; /** @@ -128,9 +124,15 @@ public class MultiResolutionImageReaderTest extends Camera2AndroidTestCase { isLogicalCamera || isUltraHighResCamera); for (int format : multiResolutionOutputFormats) { - assertTrue(String.format("Camera %s: multi-resolution output format %d " - + "isn't a supported format", id, format), - CameraTestUtils.contains(outputFormats, format)); + // Multi-resolution output format must be one of the supports stream configuration + // map formats, with the exception of RAW. It's valid for the camera device not to + // support RAW, but the multi-resolution ImageReader does. + if (format != ImageFormat.RAW_SENSOR && format != ImageFormat.RAW10 + && format != ImageFormat.RAW12 && format != ImageFormat.RAW_PRIVATE) { + assertTrue(String.format("Camera %s: multi-resolution output format %d " + + "isn't a supported format", id, format), + CameraTestUtils.contains(outputFormats, format)); + } Collection<MultiResolutionStreamInfo> multiResolutionStreams = multiResolutionMap.getOutputInfo(format); @@ -522,6 +524,7 @@ public class MultiResolutionImageReaderTest extends Camera2AndroidTestCase { img.close(); numImageVerified++; + retryCount = 0; } } } diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java index df85f466b9e..49614f2260c 100644 --- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java @@ -1218,6 +1218,10 @@ public class RecordingTest extends Camera2SurfaceViewTestCase { previewFrameRate = previewRateMap.get(captureRate); Log.v(TAG, "previewFrameRate: " + previewFrameRate + " captureRate: " + captureRate); + + Range<Integer> previewfpsRange = + new Range<Integer>(previewFrameRate, captureRate); + // Skip the test if the highest recording FPS supported by CamcorderProfile if (fpsRange.getUpper() > getFpsFromHighSpeedProfileForSize(size)) { Log.w(TAG, "high speed recording " + size + "@" + captureRate + "fps" @@ -1230,7 +1234,7 @@ public class RecordingTest extends Camera2SurfaceViewTestCase { // prepare preview surface by using video size. updatePreviewSurfaceWithVideo(size, captureRate); - startConstrainedPreview(fpsRange, previewResultListener); + startConstrainedPreview(previewfpsRange, previewResultListener); mOutMediaFileName = mDebugFileNameBase + "/test_cslowMo_video_" + captureRate + "fps_" + id + "_" + size.toString() + ".mp4"; @@ -1278,7 +1282,7 @@ public class RecordingTest extends Camera2SurfaceViewTestCase { // Stop recording and preview stopRecording(/*useMediaRecorder*/true); - startConstrainedPreview(fpsRange, previewResultListener); + startConstrainedPreview(previewfpsRange, previewResultListener); // Convert number of frames camera produced into the duration in unit of ms. float frameDurationMs = 1000.0f / videoFrameRate; 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 37f6fa43c97..282269cd69a 100644 --- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java +++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java @@ -761,9 +761,6 @@ public class CameraTestUtils extends Assert { image = mLastReader.acquireLatestImage(); if (VERBOSE) Log.v(TAG, "acquireLatestImage from " + mLastReader.toString() + " produces " + image); - if (image == null) { - return null; - } } else { fail("invalid image reader"); } @@ -772,7 +769,7 @@ public class CameraTestUtils extends Assert { } else { fail("wait for image available time out after " + timeoutMs + "ms"); } - return new ImageAndMultiResStreamInfo(image, + return image == null ? null : new ImageAndMultiResStreamInfo(image, mOwner.getStreamInfoForImageReader(mLastReader)); } else { ImageAndMultiResStreamInfo imageAndInfo = mQueue.poll(timeoutMs, diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java index f85d895d643..31eaebecfd8 100644 --- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java +++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java @@ -71,13 +71,14 @@ import com.android.eventlib.truth.EventLogsSubject; import com.android.queryable.queries.ActivityQuery; import org.junit.ClassRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; // TODO(b/228016400): replace usages of createAndProvisionManagedProfile with a nene API @RunWith(BedsteadJUnit4.class) -public class DevicePolicyManagementRoleHolderTest { +public class DevicePolicyManagementRoleHolderTest { // TODO: This is crashing on non-headless - figure it out - on headless it d't run with btest so follow up.... @ClassRule @Rule public static final DeviceState sDeviceState = new DeviceState(); @@ -135,6 +136,7 @@ public class DevicePolicyManagementRoleHolderTest { + ".TestAppAccountAuthenticatorService")) .get(); + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "new test") @RequireFeature(FEATURE_MANAGED_USERS) @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS) @@ -174,6 +176,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "new test") @RequireFeature(FEATURE_MANAGED_USERS) @EnsureHasDeviceOwner @@ -216,6 +219,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "new test") @RequireFeature(FEATURE_MANAGED_USERS) @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS) @@ -246,6 +250,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "new test") @RequireFeature(FEATURE_MANAGED_USERS) @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS) @@ -277,6 +282,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "new test") @RequireFeature(FEATURE_MANAGED_USERS) @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS) @@ -308,6 +314,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "New test") @Test @EnsureHasPermission(MANAGE_ROLE_HOLDERS) @@ -326,6 +333,7 @@ public class DevicePolicyManagementRoleHolderTest { } // TODO(b/222669810): add ensureHasNoAccounts annotation + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "New test") @Test @EnsureHasPermission(MANAGE_ROLE_HOLDERS) @@ -350,6 +358,7 @@ public class DevicePolicyManagementRoleHolderTest { } // TODO(b/222669810): add ensureHasNoAccounts annotation + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "New test") @Test @RequireFeature(FEATURE_MANAGED_USERS) @@ -373,6 +382,7 @@ public class DevicePolicyManagementRoleHolderTest { .isFalse(); } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "New test") @Test @EnsureHasPermission(MANAGE_ROLE_HOLDERS) @@ -393,6 +403,7 @@ public class DevicePolicyManagementRoleHolderTest { } } + @Ignore("b/268616097 fix issue with pre-existing accounts on the device") @Postsubmit(reason = "New test") @Test @EnsureDoesNotHavePermission(MANAGE_ROLE_HOLDERS) diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java index ae9ced5fd3a..7a056ded5c0 100644 --- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java +++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java @@ -1150,6 +1150,7 @@ public final class DevicePolicyManagerTest { @Postsubmit(reason = "New test") @Test @EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS) + @RequireFeature(FEATURE_MANAGED_USERS) @RequireDoesNotHaveFeature(FEATURE_DEVICE_ADMIN) public void checkProvisioningPreCondition_withoutDeviceAdminFeature_returnsDeviceAdminNotSupported() { assertThat( diff --git a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java index 230b75a44a8..f6ff30302d6 100644 --- a/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java +++ b/tests/devicestate/src/android/hardware/devicestate/cts/DeviceStateManagerTests.java @@ -176,7 +176,8 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { * triggered with a value equal to the requested state. */ @Test - public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest() { + public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest() + throws Throwable { final DeviceStateManager manager = getDeviceStateManager(); final int[] supportedStates = manager.getSupportedStates(); @@ -209,7 +210,7 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { // checks that we were able to find a valid state to request. assumeTrue(nextState != INVALID_DEVICE_STATE); - activity.requestDeviceStateChange(nextState); + runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState)); PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState); @@ -269,7 +270,7 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { * in a registered callback being triggered with a value equal to the base state. */ @Test - public void testCancelStateRequestFromNewActivity() throws IllegalArgumentException { + public void testCancelStateRequestFromNewActivity() throws Throwable { final DeviceStateManager manager = getDeviceStateManager(); final int[] supportedStates = manager.getSupportedStates(); // We want to verify that the app can change device state @@ -292,7 +293,7 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { DEFAULT_DISPLAY ); - DeviceStateTestActivity activity = activitySession.getActivity(); + final DeviceStateTestActivity activity = activitySession.getActivity(); int originalState = callback.mCurrentState; @@ -303,7 +304,7 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { // checks that we were able to find a valid state to request. assumeTrue(nextState != INVALID_DEVICE_STATE); - activity.requestDeviceStateChange(nextState); + runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState)); PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == nextState); @@ -322,8 +323,8 @@ public class DeviceStateManagerTests extends DeviceStateManagerTestBase { // and launching the second activity. assertEquals(nextState, callback.mCurrentState); - activity = secondActivitySession.getActivity(); - activity.cancelOverriddenState(); + final DeviceStateTestActivity activity2 = secondActivitySession.getActivity(); + activity2.cancelOverriddenState(); PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState == originalState); diff --git a/tests/framework/base/windowmanager/jetpack/SecondApp/src/android/server/wm/jetpack/second/SecondActivityKnownEmbeddingCerts.java b/tests/framework/base/windowmanager/jetpack/SecondApp/src/android/server/wm/jetpack/second/SecondActivityUnknownEmbeddingCerts.java index 9bf28dc730b..c6a7c9b45b7 100644 --- a/tests/framework/base/windowmanager/jetpack/SecondApp/src/android/server/wm/jetpack/second/SecondActivityKnownEmbeddingCerts.java +++ b/tests/framework/base/windowmanager/jetpack/SecondApp/src/android/server/wm/jetpack/second/SecondActivityUnknownEmbeddingCerts.java @@ -22,5 +22,5 @@ import android.app.Activity; * A test activity that requests trusted host certificates for embedding that does not match the * certificate of the host in CTS tests from 'android.server.wm.jetpack'. */ -public class SecondActivityKnownEmbeddingCerts extends Activity { +public class SecondActivityUnknownEmbeddingCerts extends 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 18fe90ec6b9..57a9fd56093 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 @@ -69,13 +69,15 @@ public class ActivityEmbeddingBoundsTests extends ActivityEmbeddingTestBase { 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 = createSplitPairRuleBuilderWithJava8Predicate( 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)); @@ -93,7 +95,7 @@ public class ActivityEmbeddingBoundsTests extends ActivityEmbeddingTestBase { 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/ActivityEmbeddingLifecycleTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java index 967f776792d..7e72571cee8 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 @@ -22,6 +22,7 @@ import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildca import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit; import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertNotVisible; import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertResumed; +import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions; import static android.server.wm.lifecycle.LifecycleConstants.ON_CREATE; import static android.server.wm.lifecycle.LifecycleConstants.ON_DESTROY; import static android.server.wm.lifecycle.LifecycleConstants.ON_PAUSE; @@ -40,6 +41,7 @@ import android.app.Activity; import android.app.Application; import android.net.Uri; import android.os.Bundle; +import android.server.wm.jetpack.utils.JavaConsumerAdapter; import android.server.wm.jetpack.utils.TestActivityWithId; import android.server.wm.jetpack.utils.TestActivityWithId2; import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity; @@ -80,7 +82,13 @@ public class ActivityEmbeddingLifecycleTests extends ActivityEmbeddingTestBase { public void setUp() { super.setUp(); mSplitInfoConsumer = new SplitInfoLifecycleConsumer<>(); - mActivityEmbeddingComponent.setSplitInfoCallback(mSplitInfoConsumer); + if (getWindowExtensions().getVendorApiLevel() >= 2) { + mActivityEmbeddingComponent.setSplitInfoCallback(mSplitInfoConsumer); + } else { + mActivityEmbeddingComponent.setSplitInfoCallback( + new JavaConsumerAdapter<>(mSplitInfoConsumer) + ); + } mEventLogClient = EventLogClient.create(TEST_OWNER, mInstrumentation.getTargetContext(), Uri.parse("content://android.server.wm.jetpack.logprovider")); 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 e7235a2a4d0..0a105cf7742 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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase @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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase 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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase */ @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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase 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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase @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 @@ public class ActivityEmbeddingPlaceholderTests extends ActivityEmbeddingTestBase 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/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java index fb9f5e8ccb5..2c8c843bb79 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 @@ -186,6 +186,11 @@ public class WindowManagerJetpackTestBase { .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/src/android/server/wm/ActivityMetricsLoggerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java index 9293ed96f74..ff195a14530 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java @@ -162,6 +162,7 @@ public class ActivityMetricsLoggerTests extends ActivityManagerTestBase { } private void assertTransitionIsStartingWindow(LogMaker log) { + if (isLeanBack()) return; assertEquals("transition should be started because of starting window", 1 /* APP_TRANSITION_STARTING_WINDOW */, log.getSubtype()); assertNotNull("log should have starting window delay", 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 b585c048c4b..4463efe0b3b 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardTransitionTests.java @@ -155,7 +155,7 @@ public class KeyguardTransitionTests extends ActivityManagerTestBase { @Test public void testNewActivityDuringOccludedWithAttr() { final LockScreenSession lockScreenSession = createManagedLockScreenSession(); - launchActivity(SHOW_WHEN_LOCKED_ATTR_NO_PREVIEW_ACTIVITY); + launchActivityInFullscreen(SHOW_WHEN_LOCKED_ATTR_NO_PREVIEW_ACTIVITY); lockScreenSession.gotoKeyguard(SHOW_WHEN_LOCKED_ATTR_NO_PREVIEW_ACTIVITY); launchActivity(SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY); mWmState.computeState(SHOW_WHEN_LOCKED_WITH_DIALOG_NO_PREVIEW_ACTIVITY); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java index 5f96dd32241..1a452c05b4d 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/RoundedCornerTests.java @@ -136,8 +136,6 @@ public class RoundedCornerTests extends ActivityManagerTestBase { }); // Make sure the child window has been laid out. - final View childWindowRoot = activity.getChildWindowRoot(); - PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot.getWidth() > 0); PollingCheck.waitFor(TIMEOUT, () -> activity.getDispatchedInsets() != null); final WindowInsets insets = activity.getDispatchedInsets(); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java index 4958cc1bf9c..f6c13120b67 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java @@ -167,6 +167,7 @@ public class SplashscreenTests extends ActivityManagerTestBase { // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly // applied insets by system bars in AAOS. assumeFalse(isCar()); + assumeFalse(isLeanBack()); final CommandSession.ActivitySession starter = prepareTestStarter(); final ActivityOptions noIconOptions = ActivityOptions.makeBasic() @@ -438,6 +439,7 @@ public class SplashscreenTests extends ActivityManagerTestBase { // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly // applied insets by system bars in AAOS. assumeFalse(isCar()); + assumeFalse(isLeanBack()); final CommandSession.ActivitySession starter = prepareTestStarter(); final ActivityOptions noIconOptions = ActivityOptions.makeBasic() @@ -506,6 +508,7 @@ public class SplashscreenTests extends ActivityManagerTestBase { // TODO(b/192431448): Allow Automotive to skip this test until Splash Screen is properly // applied insets by system bars in AAOS. assumeFalse(isCar()); + assumeFalse(isLeanBack()); final LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); final ShortcutManager shortcutManager = mContext.getSystemService(ShortcutManager.class); diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java index 74d06b943f6..ddc1411c3dc 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java @@ -49,7 +49,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import com.android.compatibility.common.util.OverrideAnimationScaleRule; + import org.junit.Assert; +import org.junit.Rule; +import org.junit.rules.TestRule; import org.mockito.InOrder; import java.util.ArrayList; @@ -63,6 +67,10 @@ import java.util.function.Predicate; */ public class WindowInsetsAnimationTestBase extends WindowManagerTestBase { + @Rule + public final OverrideAnimationScaleRule mOverrideAnimationScaleRule = + new OverrideAnimationScaleRule(1.0f); + protected TestActivity mActivity; protected View mRootView; diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java index f3ed79f804e..0c376ae6e49 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowTest.java @@ -676,17 +676,20 @@ public class WindowTest { @Test public void testSetFitsContentForInsets_displayCutoutInsets_areApplied() throws Throwable { - setMayAffectDisplayRotation(); - mActivityRule.runOnUiThread(() -> { - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - mWindow.setDecorFitsSystemWindows(true); - WindowManager.LayoutParams attrs = mWindow.getAttributes(); - attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mWindow.setAttributes(attrs); - }); - mInstrumentation.waitForIdleSync(); - assertEquals(mActivity.getContentView().getRootWindowInsets().getSystemWindowInsets(), - mActivity.getAppliedInsets()); + try (IgnoreOrientationRequestSession session = + new IgnoreOrientationRequestSession(false /* enable */)) { + setMayAffectDisplayRotation(); + mActivityRule.runOnUiThread(() -> { + mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + mWindow.setDecorFitsSystemWindows(true); + WindowManager.LayoutParams attrs = mWindow.getAttributes(); + attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + mWindow.setAttributes(attrs); + }); + mInstrumentation.waitForIdleSync(); + assertEquals(mActivity.getContentView().getRootWindowInsets().getSystemWindowInsets(), + mActivity.getAppliedInsets()); + } } @Test diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java index cc4552decff..04d18faa595 100644 --- a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java +++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java @@ -33,6 +33,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.Activity; @@ -76,6 +77,7 @@ import androidx.annotation.Nullable; import androidx.test.ext.junit.rules.ActivityScenarioRule; import com.android.compatibility.common.util.AppOpsUtils; +import com.android.compatibility.common.util.FeatureUtil; import com.android.compatibility.common.util.SystemUtil; import org.junit.After; @@ -805,6 +807,7 @@ public class WindowUntrustedTouchTest { @Test public void testWhenTextToastWindow_allowsTouch() throws Throwable { + assumeFalse("Watch does not support new Toast behavior yet.", FeatureUtil.isWatch()); addToastOverlay(APP_A, /* custom */ false); Rect toast = mWmState.waitForResult("toast bounds", state -> state.findFirstWindowWithType(LayoutParams.TYPE_TOAST).getFrame()); 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 03988ea28af..46081611198 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 @@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_HOME; @@ -348,6 +349,11 @@ public abstract class ActivityManagerTestBase { extras); } + protected static String getAmStartCmdWithWindowingMode( + final ComponentName activityName, int windowingMode) { + return getAmStartCmdInNewTask(activityName) + " --windowingMode " + windowingMode; + } + protected WindowManagerStateHelper mWmState = new WindowManagerStateHelper(); protected TouchHelper mTouchHelper = new TouchHelper(mInstrumentation, mWmState); // Initialized in setUp to execute with proper permission, such as MANAGE_ACTIVITY_TASKS @@ -829,6 +835,12 @@ public abstract class ActivityManagerTestBase { mWmState.waitForValidState(activityName); } + protected void launchActivityInFullscreen(final ComponentName activityName) { + executeShellCommand( + getAmStartCmdWithWindowingMode(activityName, WINDOWING_MODE_FULLSCREEN)); + mWmState.waitForValidState(activityName); + } + protected static void waitForIdle() { getInstrumentation().waitForIdleSync(); } diff --git a/tests/inputmethod/AndroidTest.xml b/tests/inputmethod/AndroidTest.xml index 78d878bdef7..8f2225294aa 100644 --- a/tests/inputmethod/AndroidTest.xml +++ b/tests/inputmethod/AndroidTest.xml @@ -116,6 +116,9 @@ <option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS com.android.cts.mocka11yime" /> <option name="run-command" value="am compat enable ALLOW_TEST_API_ACCESS android.view.inputmethod.ctstestapp" /> <option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS android.view.inputmethod.ctstestapp" /> + + <!-- Wait for PACKAGE_ADDED broadcasts to be delivered to InputMethodManagerService. --> + <option name="run-command" value="am wait-for-broadcast-idle" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.view.inputmethod.cts" /> diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java index 0fa03072b1c..4d4bdef8134 100644 --- a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java +++ b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java @@ -18,6 +18,7 @@ package android.view.inputmethod.cts; import static android.view.WindowInsets.CONSUMED; import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.navigationBars; import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput; import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand; @@ -26,7 +27,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import android.app.WindowConfiguration; -import android.graphics.Point; import android.os.Process; import android.os.SystemClock; import android.util.Pair; @@ -91,7 +91,7 @@ public class ImeInsetsControllerTest extends EndToEndImeTestBase { } private static final int INITIAL_KEYBOARD_HEIGHT = 200; - private static final int NEW_KEYBOARD_HEIGHT = 300; + private static final int KEYBOARD_HEIGHT_INCREASE = 100; @Test public void testChangeSizeWhileControlling() throws Exception { @@ -152,7 +152,9 @@ public class ImeInsetsControllerTest extends EndToEndImeTestBase { // Change keyboard height, but make sure the insets don't change until the controlling // is done. - expectCommand(stream, imeSession.callSetHeight(NEW_KEYBOARD_HEIGHT), TIMEOUT); + final int newKeyboardHeight = + lastInsets[0].getInsets(ime()).bottom + KEYBOARD_HEIGHT_INCREASE; + expectCommand(stream, imeSession.callSetHeight(newKeyboardHeight), TIMEOUT); SystemClock.sleep(500); @@ -174,8 +176,8 @@ public class ImeInsetsControllerTest extends EndToEndImeTestBase { assertEquals(0, insetsLatch.getCount()); // Verify new height - assertEquals(getExpectedBottomInsets(NEW_KEYBOARD_HEIGHT, decorView), - lastInsets[0].getInsets(ime()).bottom); + assertEquals(getExpectedBottomInsets(newKeyboardHeight, decorView), + lastInsets[0].getInsets(ime()).bottom); assertFalse(cancelled[0]); } @@ -206,22 +208,10 @@ public class ImeInsetsControllerTest extends EndToEndImeTestBase { }; } - private int getDisplayHeight(View view) { - final Point size = new Point(); - view.getDisplay().getRealSize(size); - return size.y; - } - - private int getBottomOfWindow(View decorView) { - final int[] viewPos = new int[2]; - decorView.getLocationOnScreen(viewPos); - return decorView.getHeight() + viewPos[1]; - } - private int getExpectedBottomInsets(int keyboardHeight, View decorView) { - return Math.max( - 0, - keyboardHeight - - Math.max(0, getDisplayHeight(decorView) - getBottomOfWindow(decorView))); + // IME window is never smaller than navigation bars. + final int navBarHeight = decorView.getRootWindowInsets() + .getInsetsIgnoringVisibility(navigationBars()).bottom; + return Math.max(navBarHeight, keyboardHeight); } } diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java index 8e18ec1af98..a9cec5104ef 100644 --- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java +++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceTest.java @@ -41,10 +41,12 @@ 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.app.Activity; import android.app.Instrumentation; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.Matrix; import android.graphics.RectF; import android.inputmethodservice.InputMethodService; @@ -713,6 +715,8 @@ public class InputMethodServiceTest extends EndToEndImeTestBase { @Test public void testBatchEdit_commitAndSetComposingRegion_webView() throws Exception { + assumeTrue(hasFeatureWebView()); + getCommitAndSetComposingRegionTest(TIMEOUT, "testBatchEdit_commitAndSetComposingRegion_webView/") .setTestTextView(false) @@ -729,6 +733,8 @@ public class InputMethodServiceTest extends EndToEndImeTestBase { @Test public void testBatchEdit_commitSpaceThenSetComposingRegion_webView() throws Exception { + assumeTrue(hasFeatureWebView()); + getCommitSpaceAndSetComposingRegionTest(TIMEOUT, "testBatchEdit_commitSpaceThenSetComposingRegion_webView/") .setTestTextView(false) @@ -747,12 +753,20 @@ public class InputMethodServiceTest extends EndToEndImeTestBase { @Test public void testBatchEdit_getCommitSpaceAndSetComposingRegionTestInSelectionTest_webView() throws Exception { + assumeTrue(hasFeatureWebView()); + getCommitSpaceAndSetComposingRegionInSelectionTest(TIMEOUT, "testBatchEdit_getCommitSpaceAndSetComposingRegionTestInSelectionTest_webView/") .setTestTextView(false) .runTest(); } + private boolean hasFeatureWebView() { + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW); + } + @Test public void testImeVisibleAfterRotation() throws Exception { try (MockImeSession imeSession = MockImeSession.create( diff --git a/tests/inputmethod/tests32/AndroidTest.xml b/tests/inputmethod/tests32/AndroidTest.xml index 9c5b12879de..e24e28df3c3 100644 --- a/tests/inputmethod/tests32/AndroidTest.xml +++ b/tests/inputmethod/tests32/AndroidTest.xml @@ -71,6 +71,9 @@ <option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS com.android.cts.mockime" /> <option name="run-command" value="am compat enable ALLOW_TEST_API_ACCESS android.view.inputmethod.ctstestapp" /> <option name="teardown-command" value="am compat reset ALLOW_TEST_API_ACCESS android.view.inputmethod.ctstestapp" /> + + <!-- Wait for PACKAGE_ADDED broadcasts to be delivered to InputMethodManagerService. --> + <option name="run-command" value="am wait-for-broadcast-idle" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest"> <option name="package" value="android.view.inputmethod.cts.sdk32" /> 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 ded4ecaffe9..b4c5c834595 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 @@ -86,13 +86,16 @@ public class LocationDisabledAppOpsTest { 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) - && !mLm.isProviderPackage(null, pi.packageName, null)) { + && !isProvider[0]) { bypassedNoteOps.add(pi.packageName); } }); @@ -102,8 +105,9 @@ public class LocationDisabledAppOpsTest { runWithShellPermissionIdentity(() -> { mode[0] = mAom .checkOpNoThrow(OPSTR_FINE_LOCATION, ai.uid, ai.packageName); + isProvider[0] = mLm.isProviderPackage(null, pi.packageName, null); if (mode[0] == MODE_ALLOWED && !ignoreList.includes(pi.packageName) - && !mLm.isProviderPackage(null, pi.packageName, null)) { + && !isProvider[0]) { bypassedCheckOps.add(pi.packageName); } }); diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml index ef8c1a8271c..3eab6325f28 100644 --- a/tests/tests/app/AndroidManifest.xml +++ b/tests/tests/app/AndroidManifest.xml @@ -22,7 +22,7 @@ <uses-library android:name="android.test.runner" /> <activity android:name=".ApplyOverrideConfigurationActivity" - android:configChanges="orientation|screenSize" /> + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" /> <activity android:name=".PictureInPictureActivity" android:resizeableActivity="false" diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java index 755ac444f19..6ea60236a8e 100644 --- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java +++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java @@ -17,6 +17,7 @@ package android.appenumeration.cts; import static android.Manifest.permission.SET_PREFERRED_APPLICATIONS; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.appenumeration.cts.Constants.ACTION_AWAIT_LAUNCHER_APPS_CALLBACK; import static android.appenumeration.cts.Constants.ACTION_AWAIT_LAUNCHER_APPS_SESSION_CALLBACK; import static android.appenumeration.cts.Constants.ACTION_BIND_SERVICE; @@ -163,6 +164,7 @@ import static org.junit.Assume.assumeTrue; import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; +import android.app.ActivityOptions; import android.app.PendingIntent; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; @@ -2532,7 +2534,10 @@ public class AppEnumerationTests { AmUtils.waitForBroadcastIdle(); startAndWaitForCommandReady(intent); } else { - InstrumentationRegistry.getInstrumentation().getContext().startActivity(intent); + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + InstrumentationRegistry.getInstrumentation().getContext().startActivity( + intent, options.toBundle()); } return () -> { if (!latch.block(TimeUnit.SECONDS.toMillis(10))) { diff --git a/tests/tests/bluetooth/AndroidManifest.xml b/tests/tests/bluetooth/AndroidManifest.xml index e624d2b2ab7..a1512005e4e 100644 --- a/tests/tests/bluetooth/AndroidManifest.xml +++ b/tests/tests/bluetooth/AndroidManifest.xml @@ -27,6 +27,7 @@ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java index ed42e79c06b..80229ec9638 100644 --- a/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java +++ b/tests/tests/car/src/android/car/cts/CarServiceHelperServiceUpdatableTest.java @@ -43,6 +43,7 @@ import androidx.test.filters.FlakyTest; import com.android.compatibility.common.util.SystemUtil; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.io.BufferedReader; @@ -66,6 +67,7 @@ public final class CarServiceHelperServiceUpdatableTest extends CarApiTestBase { } @Test + @Ignore("b/234674080") public void testCarServiceHelperServiceDump() throws Exception { assumeThat("System_server_dumper not implemented.", executeShellCommand("service check system_server_dumper"), diff --git a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContractIntentsTest.java b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContractIntentsTest.java index 488547d042c..9edc805da2e 100644 --- a/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContractIntentsTest.java +++ b/tests/tests/contactsprovider/src/android/provider/cts/contacts/ContactsContractIntentsTest.java @@ -56,8 +56,12 @@ public class ContactsContractIntentsTest extends AndroidTestCase { } public void testSetDefaultAccount() { - Intent intent = new Intent(ContactsContract.Settings.ACTION_SET_DEFAULT_ACCOUNT); PackageManager packageManager = getContext().getPackageManager(); + if (packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) { + return; // Skip test on watch since the intent is not required. + } + + Intent intent = new Intent(ContactsContract.Settings.ACTION_SET_DEFAULT_ACCOUNT); List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0); assertNotNull("Missing ResolveInfo", resolveInfoList); int handlerCount = 0; diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java index 5db5f661d61..d3e4c91ad8a 100644 --- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java +++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java @@ -28,6 +28,8 @@ import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.systemBars; +import static android.server.wm.ActivityManagerTestBase.isTablet; + import android.app.Activity; import android.content.Intent; import android.content.pm.ActivityInfo; diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java index c0ef37498ca..dd0cc92e4a1 100644 --- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java +++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java @@ -40,6 +40,7 @@ import androidx.test.filters.LargeTest; import androidx.test.filters.SmallTest; import androidx.test.rule.ActivityTestRule; +import com.android.compatibility.common.util.OverrideAnimationScaleRule; import com.android.compatibility.common.util.SynchronousPixelCopy; import com.android.compatibility.common.util.SystemUtil; import com.android.compatibility.common.util.WidgetTestUtils; @@ -63,6 +64,12 @@ public class AnimatedVectorDrawableParameterizedTest { public ActivityTestRule<DrawableStubActivity> mActivityRule = new ActivityTestRule<>(DrawableStubActivity.class); + // Some of these tests require animations to work normally, which may not be the case + // depending on the current state of the test device + @Rule + public final OverrideAnimationScaleRule animationScaleRule = + new OverrideAnimationScaleRule(1f); + private static final int IMAGE_WIDTH = 64; private static final int IMAGE_HEIGHT = 64; private static final long MAX_TIMEOUT_MS = 1000; diff --git a/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationIntegrationTest.kt b/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationIntegrationTest.kt index 3a9969e11b9..a7c5f490573 100644 --- a/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationIntegrationTest.kt +++ b/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationIntegrationTest.kt @@ -64,7 +64,6 @@ import org.junit.Assert.assertTrue import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.BeforeClass -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -138,7 +137,6 @@ class AppHibernationIntegrationTest { } @Test - @Ignore("b/201545116") fun testUnusedApp_getsForceStopped() { withUnusedThresholdMs(TEST_UNUSED_THRESHOLD) { withApp(APK_PATH_S_APP, APK_PACKAGE_NAME_S_APP) { diff --git a/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationUtils.kt b/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationUtils.kt index 485a4efe431..b6f03c87203 100644 --- a/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationUtils.kt +++ b/tests/tests/hibernation/src/android/hibernation/cts/AppHibernationUtils.kt @@ -328,14 +328,18 @@ fun waitFindObject(uiAutomation: UiAutomation, selector: BySelector): UiObject2 val title = ui.depthFirstSearch { node -> node.viewIdResourceName?.contains("alertTitle") == true } - val okButton = ui.depthFirstSearch { node -> - node.textAsString?.equals("OK", ignoreCase = true) ?: false + val okCloseButton = ui.depthFirstSearch { node -> + (node.textAsString?.equals("OK", ignoreCase = true) ?: false) || + (node.textAsString?.equals("Close app", ignoreCase = true) ?: false) } - - if (title?.text?.toString() == "Android System" && okButton != null) { + val titleString = title?.text?.toString() + if (okCloseButton != null && + titleString != null && + (titleString == "Android System" || + titleString.endsWith("keeps stopping"))) { // Auto dismiss occasional system dialogs to prevent interfering with the test android.util.Log.w(AutoRevokeTest.LOG_TAG, "Ignoring exception", e) - okButton.click() + okCloseButton.click() return UiAutomatorUtils.waitFindObject(selector) } else { throw e diff --git a/tests/tests/hibernation/src/android/hibernation/cts/AutoRevokeTest.kt b/tests/tests/hibernation/src/android/hibernation/cts/AutoRevokeTest.kt index 1adc0281893..34ad254ff2f 100644 --- a/tests/tests/hibernation/src/android/hibernation/cts/AutoRevokeTest.kt +++ b/tests/tests/hibernation/src/android/hibernation/cts/AutoRevokeTest.kt @@ -194,7 +194,6 @@ class AutoRevokeTest { @AppModeFull(reason = "Uses separate apps for testing") @Test - @Ignore("b/201545116") fun testUnusedApp_uninstallApp() { assumeFalse( "Unused apps screen may be unavailable on TV", diff --git a/tests/tests/media/common/src/android/media/cts/TestUtils.java b/tests/tests/media/common/src/android/media/cts/TestUtils.java index 20bf143ca96..552cf65372a 100644 --- a/tests/tests/media/common/src/android/media/cts/TestUtils.java +++ b/tests/tests/media/common/src/android/media/cts/TestUtils.java @@ -187,13 +187,27 @@ public final class TestUtils { return true; } // MTS mode, just the codecs that live in the modules - if (name.startsWith("c2.android.")) { + if (isMainlineCodec(name)) { return true; } Log.d(TAG, "Test mode MTS does not test codec " + name); return false; } + /* + * Report whether this codec is a google-supplied codec that lives within the + * mainline modules. + * + * @param name the name of a codec + * @return {@code} true if the codec is one that lives within the mainline boundaries + */ + public static boolean isMainlineCodec(String name) { + if (name.startsWith("c2.android.")) { + return true; + } + return false; + } + private TestUtils() { } 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 c9823760671..1a1280cbe90 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 @@ -27,6 +27,8 @@ import android.graphics.Bitmap; import android.media.MediaFormat; import android.media.cts.MediaHeavyPresubmitTest; import android.media.cts.TestArgs; +import android.media.cts.TestUtils; +import android.os.Build; import android.os.Environment; import android.platform.test.annotations.AppModeFull; import android.util.Log; @@ -34,6 +36,7 @@ import android.view.View; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.compatibility.common.util.ApiLevelUtil; import com.android.compatibility.common.util.MediaUtils; import java.io.File; @@ -64,6 +67,10 @@ import org.junit.Test; @AppModeFull(reason = "There should be no instant apps specific behavior related to accuracy") public class DecodeAccuracyTest extends DecodeAccuracyTestBase { + private static final boolean IS_AT_LEAST_U = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU) + || ApiLevelUtil.codenameEquals("UpsideDownCake"); + private static final boolean IS_BEFORE_U = !IS_AT_LEAST_U; + private static final String TAG = DecodeAccuracyTest.class.getSimpleName(); private static final Field[] fields = R.raw.class.getFields(); private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90; @@ -281,7 +288,7 @@ public class DecodeAccuracyTest extends DecodeAccuracyTestBase { final int golden = getGoldenId(vf.getDescription(), vf.getOriginalSize()); assertTrue("No golden found.", golden != 0); decodeVideo(vf, videoViewFactory, decoderName); - validateResult(vf, videoViewFactory.getVideoViewSnapshot(), golden); + validateResult(vf, videoViewFactory.getVideoViewSnapshot(), golden, decoderName); } private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory, @@ -293,12 +300,24 @@ public class DecodeAccuracyTest extends DecodeAccuracyTestBase { } private void validateResult( - VideoFormat videoFormat, VideoViewSnapshot videoViewSnapshot, int goldenId) { + VideoFormat videoFormat, VideoViewSnapshot videoViewSnapshot, int goldenId, + String decoderName) { final Bitmap result = checkNotNull("The expected bitmap from snapshot is null", getHelper().generateBitmapFromVideoViewSnapshot(videoViewSnapshot)); final Bitmap golden = getHelper().generateBitmapFromImageResourceId(goldenId); + + int ignorePixels = 0; + if (IS_BEFORE_U && TestUtils.isMtsMode()) { + if (TestUtils.isMainlineCodec(decoderName)) { + // some older systems don't give proper behavior at the edges (in system code). + // while we can't fix the behavior at the edges, we can verify that the rest + // of the image is within tolerance. b/256807044 + ignorePixels = 1; + } + } final BitmapCompare.Difference difference = BitmapCompare.computeMinimumDifference( - result, golden, videoFormat.getOriginalWidth(), videoFormat.getOriginalHeight()); + result, golden, ignorePixels, videoFormat.getOriginalWidth(), + videoFormat.getOriginalHeight()); if (difference.greatestPixelDifference > ALLOWED_GREATEST_PIXEL_DIFFERENCE) { /* save failing file */ 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 d26c45ffd33..38fdb1858ad 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 @@ -1763,6 +1763,7 @@ class FilenameParser { * CIE L*a*b* color space. The euclidean distance formula is used to determine pixel differences. */ class BitmapCompare { + private static final String TAG = "BitmapCompare"; private static final int RED = 0; private static final int GREEN = 1; @@ -1776,6 +1777,8 @@ class BitmapCompare { /** * Produces greatest pixel between two bitmaps. Used to determine bitmap similarity. * + * This simplified variant does not ignore any edge pixels. + * * @param bitmap1 A bitmap to compare to bitmap2. * @param bitmap2 A bitmap to compare to bitmap1. * @return A {@link Difference} with an integer describing the greatest pixel difference, @@ -1783,7 +1786,26 @@ class BitmapCompare { * {@link Pair<Integer, Integer>} of the (col, row) pixel coordinate where it was first found. */ @TargetApi(12) - public static Difference computeDifference(Bitmap bitmap1, Bitmap bitmap2) { + private static Difference computeDifference(Bitmap bitmap1, Bitmap bitmap2) { + return computeDifference(bitmap1, bitmap2, 0); + } + + /** + * Produces greatest pixel between two bitmaps. Used to determine bitmap similarity. + * + * @param bitmap1 A bitmap to compare to bitmap2. + * @param bitmap2 A bitmap to compare to bitmap1. + * @param ignorePixels number of pixels at each edge where we ignore the scoring. This + * is used for mainline and older base systems to bypass an edge behavior in the + * GPU code on those systems. + * @return A {@link Difference} with an integer describing the greatest pixel difference, + * using {@link Integer#MAX_VALUE} for completely different bitmaps, and an optional + * {@link Pair<Integer, Integer>} of the (col, row) pixel coordinate where it was + * first found. + */ + @TargetApi(12) + private static Difference computeDifference(Bitmap bitmap1, Bitmap bitmap2, int ignorePixels) { + Log.i(TAG, "ignorePixels = " + ignorePixels); if (bitmap1 == null || bitmap2 == null) { return new Difference(Integer.MAX_VALUE); } @@ -1797,15 +1819,31 @@ class BitmapCompare { // euclidean distance formula. final double[][] pixels1 = convertRgbToCieLab(bitmap1); final double[][] pixels2 = convertRgbToCieLab(bitmap2); - int greatestDifference = 0; + int greatestDifference = -1; // forces a legal index later... int greatestDifferenceIndex = -1; for (int i = 0; i < pixels1.length; i++) { + // pixels within 'ignorePixels' of the edge are to be ignored for + // scoring purposes. + int x = i % bitmap1.getWidth(); + int y = i / bitmap1.getWidth(); + if (x < ignorePixels || x >= bitmap1.getWidth() - ignorePixels + || y < ignorePixels || y >= bitmap1.getHeight() - ignorePixels) { + continue; + } + final int difference = euclideanDistance(pixels1[i], pixels2[i]); + if (difference > greatestDifference) { greatestDifference = difference; greatestDifferenceIndex = i; } } + + // huge ignorePixels values can get here without checking any pixels + if (greatestDifferenceIndex == -1) { + greatestDifferenceIndex = 0; + greatestDifference = 0; + } return new Difference(greatestDifference, Pair.create( greatestDifferenceIndex % bitmap1.getWidth(), greatestDifferenceIndex / bitmap1.getWidth())); @@ -2019,16 +2057,16 @@ class BitmapCompare { */ @TargetApi(12) public static Difference computeMinimumDifference( - Bitmap bitmap1, Bitmap bitmap2, Pair<Double, Double>[] borderCrops) { + Bitmap bitmap1, Bitmap bitmap2, int ignorePixels, Pair<Double, Double>[] borderCrops) { // Compute the difference with the original image (bitmap2) first. - Difference minDiff = computeDifference(bitmap1, bitmap2); + Difference minDiff = computeDifference(bitmap1, bitmap2, ignorePixels); // Then go through the list of borderCrops. for (Pair<Double, Double> borderCrop : borderCrops) { // Compute the difference between bitmap1 and a transformed // version of bitmap2. Bitmap bitmap2s = shrinkAndScaleBilinear(bitmap2, borderCrop.first, borderCrop.second); - Difference d = computeDifference(bitmap1, bitmap2s); + Difference d = computeDifference(bitmap1, bitmap2s, ignorePixels); // Keep the minimum difference. if (d.greatestPixelDifference < minDiff.greatestPixelDifference) { minDiff = d; @@ -2043,7 +2081,7 @@ class BitmapCompare { */ @TargetApi(12) public static Difference computeMinimumDifference( - Bitmap bitmap1, Bitmap bitmap2, int trueWidth, int trueHeight) { + Bitmap bitmap1, Bitmap bitmap2, int ignorePixels, int trueWidth, int trueHeight) { double hBorder = (double) bitmap1.getWidth() / (double) trueWidth; double vBorder = (double) bitmap1.getHeight() / (double) trueHeight; @@ -2052,6 +2090,7 @@ class BitmapCompare { return computeMinimumDifference( bitmap1, bitmap2, + ignorePixels, new Pair[] { Pair.create(hBorderH, 0.0), Pair.create(hBorderH, vBorderH), diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java index ef7646b87f6..3db3d570777 100644 --- a/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java +++ b/tests/tests/media/decoder/src/android/media/decoder/cts/VideoDecoderPerfTest.java @@ -211,7 +211,7 @@ public class VideoDecoderPerfTest extends MediaTestBase { } // allow improvements in mainline-updated google-supplied software codecs. - boolean fasterIsOk = mUpdatedSwCodec & name.startsWith("c2.android."); + boolean fasterIsOk = mUpdatedSwCodec & TestUtils.isMainlineCodec(name); String error = MediaPerfUtils.verifyAchievableFrameRates(name, mime, width, height, fasterIsOk, measuredFps); diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmTest.java index 1bb5646c781..62e2f693458 100644 --- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmTest.java +++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmTest.java @@ -51,10 +51,7 @@ public class MediaDrmTest { private void testSingleScheme(UUID scheme) throws Exception { MediaDrm md = new MediaDrm(scheme); - assertTrue(md.getOpenSessionCount() <= md.getMaxSessionCount()); - assertThrows(() -> { - md.closeSession(null); - }); + // TODO(b/267460223): test properties description, vendor, version md.close(); } @@ -125,7 +122,9 @@ public class MediaDrmTest { @Test public void testPlaybackComponent() throws UnsupportedSchemeException { - for (UUID scheme : MediaDrm.getSupportedCryptoSchemes()) { + final UUID CLEARKEY_UUID = new UUID(0xe2719d58a985b3c9L, 0x781ab030af78d30eL); + // TODO(b/267463362): move testPlaybackComponent to MediaDrmClearkeyTest + for (UUID scheme : new UUID[] {CLEARKEY_UUID}) { MediaDrm drm = new MediaDrm(scheme); byte[] sid = null; try { diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java index c769a09432b..85810eb3a3f 100644 --- a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java +++ b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java @@ -57,7 +57,12 @@ public class NfcPreferredPaymentTest { private boolean supportsHardware() { final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_NFC); + boolean existAnyReqFeature = + pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF) + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE) + || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC); + return existAnyReqFeature; } @Before diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml index eafc6a6389c..c50ccb424f8 100644 --- a/tests/tests/permission/AndroidTest.xml +++ b/tests/tests/permission/AndroidTest.xml @@ -27,7 +27,10 @@ <!-- Keep screen on for Bluetooth scanning --> <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" /> + <option name="restore-settings" value="true" /> <option name="screen-always-on" value="on" /> + <option name="disable-device-config-sync" value="true" /> </target_preparer> <!-- Install main test suite apk --> diff --git a/tests/tests/permission2/AndroidTest.xml b/tests/tests/permission2/AndroidTest.xml index 54ea94b710e..59d483d40c8 100644 --- a/tests/tests/permission2/AndroidTest.xml +++ b/tests/tests/permission2/AndroidTest.xml @@ -30,6 +30,13 @@ <option name="test-file-name" value="CtsPermission2TestCases.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" /> + <option name="restore-settings" value="true" /> + <option name="disable-device-config-sync" value="true" /> + </target_preparer> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> <option name="push" value="CtsLocationPermissionsUserSdk22.apk->/data/local/tmp/cts/permissions2/CtsLocationPermissionsUserSdk22.apk" /> <option name="push" value="CtsLocationPermissionsUserSdk29.apk->/data/local/tmp/cts/permissions2/CtsLocationPermissionsUserSdk29.apk" /> diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml index aa263ea65bb..d275ef4fed9 100644 --- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml +++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml @@ -482,4 +482,8 @@ android:protectionLevel="signature|privileged" android:label="@string/car_permission_label_manage_thread_priority" android:description="@string/car_permission_desc_manage_thread_priority"/> + <permission android:name="android.car.permission.BIND_OEM_CAR_SERVICE" + android:protectionLevel="signature|privileged" + android:label="@string/car_permission_label_bind_oem_car_service" + android:description="@string/car_permission_desc_bind_oem_car_service"/> </manifest> diff --git a/tests/tests/permission2/res/raw/wear_android_manifest.xml b/tests/tests/permission2/res/raw/wear_android_manifest.xml new file mode 100644 index 00000000000..08488bc3d72 --- /dev/null +++ b/tests/tests/permission2/res/raw/wear_android_manifest.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!-- This file contains permissions which were back ported. + These permissions are already present on future platform releases. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android" coreApp="true" android:sharedUserId="android.uid.system" + android:sharedUserLabel="@string/android_system_label"> + + <!-- @hide Allows an application to access wrist temperature data from the watch sensors. + <p class="note"><strong>Note: </strong> This permission is for Wear OS only. + <p>Protection level: dangerous --> + <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_bodySensorsWristTemperature" + android:description="@string/permdesc_bodySensorsWristTemperature" + android:backgroundPermission="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" + android:protectionLevel="dangerous" /> + + <!-- @hide Allows an application to access wrist temperature data from the watch sensors. + If you're requesting this permission, you must also request + {@link #BODY_SENSORS_WRIST_TEMPERATURE}. Requesting this permission by itself doesn't + give you wrist temperature body sensors access. + <p class="note"><strong>Note: </strong> This permission is for Wear OS only. + <p>Protection level: dangerous + + <p> This is a hard restricted permission which cannot be held by an app until + the installer on record allowlists the permission. For more details see + {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}. + --> + <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" + android:permissionGroup="android.permission-group.UNDEFINED" + android:label="@string/permlab_bodySensors_wristTemperature_background" + android:description="@string/permdesc_bodySensors_wristTemperature_background" + android:protectionLevel="dangerous" + android:permissionFlags="hardRestricted" /> + +</manifest>
\ No newline at end of file diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java index 512e3782d48..637380313a2 100644 --- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java +++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java @@ -20,6 +20,8 @@ import static android.content.pm.PermissionInfo.FLAG_INSTALLED; import static android.content.pm.PermissionInfo.PROTECTION_MASK_BASE; import static android.os.Build.VERSION.SECURITY_PATCH; +import static com.android.compatibility.common.util.SystemUtil.runShellCommand; + import static com.google.common.truth.Truth.assertWithMessage; import android.Manifest; @@ -29,6 +31,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.os.Build; import android.os.Process; import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; @@ -74,10 +77,15 @@ public class PermissionPolicyTest { private static final String SET_UNRESTRICTED_GESTURE_EXCLUSION = "android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION"; + private static final String BIND_OEM_CAR_SERVICE = + "android.car.permission.BIND_OEM_CAR_SERVICE"; + private static final String RECEIVE_KEYCODE_EVENTS_PERMISSION = "android.permission.RECEIVE_KEYCODE_EVENTS"; private static final String ACCESS_SHORTCUTS_PERMISSION = "android.permission.ACCESS_SHORTCUTS"; + private static final String BIND_QUICK_SETTINGS_TILE = + "android.permission.BIND_QUICK_SETTINGS_TILE"; private static final String LOG_TAG = "PermissionProtectionTest"; @@ -168,6 +176,9 @@ public class PermissionPolicyTest { } declaredPermissionsMap.putAll(carServiceBuiltInPermissionsMap); } + if (sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { + expectedPermissions.addAll(loadExpectedPermissions(R.raw.wear_android_manifest)); + } for (ExpectedPermissionInfo expectedPermission : expectedPermissions) { String expectedPermissionName = expectedPermission.name; @@ -536,6 +547,8 @@ public class PermissionPolicyTest { return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE); case SET_UNRESTRICTED_GESTURE_EXCLUSION: return true; + case BIND_OEM_CAR_SERVICE: + return shoudldSkipBindOemCarService(); case RECEIVE_KEYCODE_EVENTS_PERMISSION: return true; default: @@ -543,9 +556,25 @@ public class PermissionPolicyTest { } } + /** + * check should be skipped only for T and T-QPR1 + */ + private boolean shoudldSkipBindOemCarService() { + if (Build.VERSION.SDK_INT > 33) { + return false; + } + String output = runShellCommand("dumpsys car_service --version"); + if (output.contains("Car API minor: 0") || output.contains("Car API minor: 1")) { + return true; + } + + return false; + } + private static boolean shouldAllowProtectionFlagsChange( String permissionName, int expectedFlags, int actualFlags) { - return ACCESS_SHORTCUTS_PERMISSION.equals(permissionName) + return (ACCESS_SHORTCUTS_PERMISSION.equals(permissionName) + || BIND_QUICK_SETTINGS_TILE.equals(permissionName)) && ((expectedFlags | PermissionInfo.PROTECTION_FLAG_RECENTS) == (actualFlags | PermissionInfo.PROTECTION_FLAG_RECENTS)); } diff --git a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt index 18557bd54d5..2a9f815aec5 100644 --- a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt +++ b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt @@ -55,6 +55,7 @@ import android.Manifest.permission.WRITE_CONTACTS import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.Manifest.permission_group.UNDEFINED import android.app.AppOpsManager.permissionToOp +import android.content.pm.PackageManager import android.content.pm.PackageManager.GET_PERMISSIONS import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP @@ -166,6 +167,23 @@ class RuntimePermissionProperties { // runtime permission expectedPerms.add(READ_MEDIA_VISUAL_USER_SELECTED) + // Add runtime permissions added in V (back ported from U) which were _not_ split from a + // previously existing runtime permission + if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) { + expectedPerms.add(BODY_SENSORS_WRIST_TEMPERATURE) + expectedPerms.add(BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND) + } + assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name }) } + + companion object { + // These permissions are back ported from Android U to tm-wear, hidden in the + // "core/res/AndroidManifest.xml" file of /framework/base repo. Added these 2 constants here + // because hidden permissions can't be imported like other imported permissions in this file + private const val BODY_SENSORS_WRIST_TEMPERATURE = + "android.permission.BODY_SENSORS_WRIST_TEMPERATURE" + private const val BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND = + "android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND" + } } diff --git a/tests/tests/permission3/AndroidTest.xml b/tests/tests/permission3/AndroidTest.xml index a2555ffcba3..68401e7fd3a 100644 --- a/tests/tests/permission3/AndroidTest.xml +++ b/tests/tests/permission3/AndroidTest.xml @@ -32,6 +32,9 @@ <!-- Keep screen on for Bluetooth scanning --> <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" /> + <option name="restore-settings" value="true" /> + <option name="disable-device-config-sync" value="true" /> <option name="screen-always-on" value="on" /> </target_preparer> diff --git a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt index 5b9db99170a..e9f6c2ab6d5 100755..100644 --- a/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/BasePermissionTest.kt @@ -49,6 +49,7 @@ abstract class BasePermissionTest { companion object { const val APK_DIRECTORY = "/data/local/tmp/cts/permission3" + const val QUICK_CHECK_TIMEOUT_MILLIS = 100L const val IDLE_TIMEOUT_MILLIS: Long = 1000 const val UNEXPECTED_TIMEOUT_MILLIS = 1000 const val TIMEOUT_MILLIS: Long = 20000 diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt index 6d476c5d762..4443fac930a 100755..100644 --- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt @@ -32,9 +32,11 @@ import android.support.test.uiautomator.UiSelector import android.text.Spanned import android.text.style.ClickableSpan import android.view.View +import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity import com.android.compatibility.common.util.SystemUtil.eventually import com.android.modules.utils.build.SdkLevel import org.junit.After +import org.junit.Assert import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -113,6 +115,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { const val REQUEST_LOCATION_MESSAGE = "permgrouprequest_location" + // The highest SDK for which the system will show a "low SDK" warning when launching the app + const val MAX_SDK_FOR_SDK_WARNING = 27 + val STORAGE_AND_MEDIA_PERMISSIONS = setOf( android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, @@ -209,8 +214,10 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { uninstallPackage(APP_PACKAGE_NAME, requireSuccess = false) } - protected fun clearTargetSdkWarning() = - click(By.res("android:id/button1")) + protected fun clearTargetSdkWarning(timeoutMillis: Long = TIMEOUT_MILLIS) = + waitFindObjectOrNull(By.res("android:id/button1"), timeoutMillis)?.click()?.also { + waitForIdle() + } protected fun clickPermissionReviewContinue() { if (isAutomotive || isWatch) { @@ -231,6 +238,8 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { protected fun approvePermissionReview() { startAppActivityAndAssertResultCode(Activity.RESULT_OK) { clickPermissionReviewContinue() + waitForIdle() + clearTargetSdkWarning() } } @@ -294,6 +303,13 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } ) waitForIdle() + + // Clear the low target SDK warning message if it's expected + if (getTargetSdk() <= MAX_SDK_FOR_SDK_WARNING) { + clearTargetSdkWarning(timeoutMillis = QUICK_CHECK_TIMEOUT_MILLIS) + waitForIdle() + } + // Notification permission prompt is shown first, so get it out of the way clickNotificationPermissionRequestAllowButtonIfAvailable() // Perform the post-request action @@ -421,6 +437,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { "com.android.permissioncontroller:id/detail_message" )[0] } + if (!node.isVisibleToUser) { + scrollToBottom() + } assertTrue(node.isVisibleToUser) val text = node.text as Spanned val clickableSpan = text.getSpans(0, text.length, ClickableSpan::class.java)[0] @@ -459,26 +478,39 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { } } - protected fun grantAppPermissions(vararg permissions: String, targetSdk: Int = 30) { - setAppPermissionState(*permissions, state = PermissionState.ALLOWED, isLegacyApp = false, - targetSdk = targetSdk) + protected fun grantAppPermissions(vararg permissions: String) { + setAppPermissionState(*permissions, state = PermissionState.ALLOWED, isLegacyApp = false) } protected fun revokeAppPermissions( vararg permissions: String, - isLegacyApp: Boolean = false, - targetSdk: Int = 30 + isLegacyApp: Boolean = false ) { setAppPermissionState(*permissions, state = PermissionState.DENIED, - isLegacyApp = isLegacyApp, targetSdk = targetSdk) + isLegacyApp = isLegacyApp) + } + + protected fun getTargetSdk(packageName: String = APP_PACKAGE_NAME): Int { + return callWithShellPermissionIdentity { + try { + context.packageManager.getApplicationInfo(packageName, 0).targetSdkVersion + } catch (e: PackageManager.NameNotFoundException) { + Assert.fail("Package $packageName not found") + -1 + } + } } private fun setAppPermissionState( vararg permissions: String, state: PermissionState, - isLegacyApp: Boolean, - targetSdk: Int + isLegacyApp: Boolean ) { + val targetSdk = getTargetSdk() + if (targetSdk <= MAX_SDK_FOR_SDK_WARNING) { + clearTargetSdkWarning(QUICK_CHECK_TIMEOUT_MILLIS) + } + if (isTv) { // Dismiss DeprecatedTargetSdkVersionDialog, if present if (waitFindObjectOrNull(By.text(APP_PACKAGE_NAME), 1000L) != null) { @@ -561,7 +593,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { By.text(getPermissionControllerString( ALLOW_FOREGROUND_PREFERENCE_TEXT)) } else { - byAnyText(getPermissionControllerResString(ALLOW_BUTTON_TEXT),getPermissionControllerResString(ALLOW_ALL_FILES_BUTTON_TEXT)) + byAnyText(getPermissionControllerResString(ALLOW_BUTTON_TEXT), + getPermissionControllerResString( + ALLOW_ALL_FILES_BUTTON_TEXT)) } PermissionState.DENIED -> if (!isLegacyApp && hasAskButton(permission)) { diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt index 8bd15373101..df2810e33d9 100644 --- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt +++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt @@ -39,9 +39,7 @@ class MediaPermissionTest : BaseUsePermissionTest() { @Test fun testWhenRESIsGrantedFromGrantDialogThenShouldGrantAllPermissions() { installPackage(APP_APK_PATH_23) - requestAppPermissionsAndAssertResult( - android.Manifest.permission.READ_EXTERNAL_STORAGE to true - ) { + requestAppPermissionsAndAssertResult(Manifest.permission.READ_EXTERNAL_STORAGE to true) { clickPermissionRequestAllowButton() } assertStorageAndMediaPermissionState(true) @@ -50,30 +48,28 @@ class MediaPermissionTest : BaseUsePermissionTest() { @Test fun testWhenRESIsGrantedManuallyThenShouldGrantAllPermissions() { installPackage(APP_APK_PATH_23) - grantAppPermissions(android.Manifest.permission.READ_EXTERNAL_STORAGE, targetSdk = 23) + grantAppPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) assertStorageAndMediaPermissionState(true) } @Test fun testWhenAuralIsGrantedManuallyThenShouldGrantAllPermissions() { installPackage(APP_APK_PATH_23) - grantAppPermissions(android.Manifest.permission.READ_MEDIA_AUDIO, targetSdk = 23) + grantAppPermissions(Manifest.permission.READ_MEDIA_AUDIO) assertStorageAndMediaPermissionState(true) } @Test fun testWhenVisualIsGrantedManuallyThenShouldGrantAllPermissions() { installPackage(APP_APK_PATH_23) - grantAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23) + grantAppPermissions(Manifest.permission.READ_MEDIA_VIDEO) assertStorageAndMediaPermissionState(true) } @Test fun testWhenRESIsDeniedFromGrantDialogThenShouldDenyAllPermissions() { installPackage(APP_APK_PATH_23) - requestAppPermissionsAndAssertResult( - android.Manifest.permission.READ_EXTERNAL_STORAGE to false - ) { + requestAppPermissionsAndAssertResult(Manifest.permission.READ_EXTERNAL_STORAGE to false) { clickPermissionRequestDenyButton() } assertStorageAndMediaPermissionState(false) @@ -82,16 +78,16 @@ class MediaPermissionTest : BaseUsePermissionTest() { @Test fun testWhenRESIsDeniedManuallyThenShouldDenyAllPermissions() { installPackage(APP_APK_PATH_23) - grantAppPermissions(android.Manifest.permission.READ_EXTERNAL_STORAGE, targetSdk = 23) - revokeAppPermissions(android.Manifest.permission.READ_EXTERNAL_STORAGE, targetSdk = 23) + grantAppPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) + revokeAppPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) assertStorageAndMediaPermissionState(false) } @Test fun testWhenAuralIsDeniedManuallyThenShouldDenyAllPermissions() { installPackage(APP_APK_PATH_23) - grantAppPermissions(android.Manifest.permission.READ_MEDIA_AUDIO, targetSdk = 23) - revokeAppPermissions(android.Manifest.permission.READ_MEDIA_AUDIO, targetSdk = 23) + grantAppPermissions(Manifest.permission.READ_MEDIA_AUDIO) + revokeAppPermissions(Manifest.permission.READ_MEDIA_AUDIO) assertStorageAndMediaPermissionState(false) } @@ -100,8 +96,8 @@ class MediaPermissionTest : BaseUsePermissionTest() { // 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) + grantAppPermissions(Manifest.permission.READ_MEDIA_VIDEO) + revokeAppPermissions(Manifest.permission.READ_MEDIA_VIDEO) assertStorageAndMediaPermissionState(false) } @@ -109,8 +105,8 @@ class MediaPermissionTest : BaseUsePermissionTest() { fun testWhenA33AppRequestsStorageThenNoDialogAndNoGrant() { installPackage(APP_APK_PATH_MEDIA_PERMISSION_33_WITH_STORAGE) requestAppPermissions( - android.Manifest.permission.READ_EXTERNAL_STORAGE, - android.Manifest.permission.WRITE_EXTERNAL_STORAGE + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE ) { } assertStorageAndMediaPermissionState(false) @@ -119,30 +115,30 @@ class MediaPermissionTest : BaseUsePermissionTest() { @Test fun testWhenA33AppRequestsAuralThenDialogAndGrant() { installPackage(APP_APK_PATH_LATEST) - requestAppPermissions(android.Manifest.permission.READ_MEDIA_AUDIO) { + requestAppPermissions(Manifest.permission.READ_MEDIA_AUDIO) { clickPermissionRequestAllowButton() } - assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false) - assertAppHasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, false) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_AUDIO, true) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_VIDEO, false) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_IMAGES, false) + assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, false) + assertAppHasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, false) + assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, true) + assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, false) + assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, false) } @Test fun testWhenA33AppRequestsVisualThenDialogAndGrant() { installPackage(APP_APK_PATH_LATEST) requestAppPermissions( - android.Manifest.permission.READ_MEDIA_VIDEO, - android.Manifest.permission.READ_MEDIA_IMAGES + Manifest.permission.READ_MEDIA_VIDEO, + Manifest.permission.READ_MEDIA_IMAGES ) { clickPermissionRequestAllowButton() } - assertAppHasPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, false) - assertAppHasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, false) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_AUDIO, false) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_VIDEO, true) - assertAppHasPermission(android.Manifest.permission.READ_MEDIA_IMAGES, true) + assertAppHasPermission(Manifest.permission.READ_EXTERNAL_STORAGE, false) + assertAppHasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, false) + assertAppHasPermission(Manifest.permission.READ_MEDIA_AUDIO, false) + assertAppHasPermission(Manifest.permission.READ_MEDIA_VIDEO, true) + assertAppHasPermission(Manifest.permission.READ_MEDIA_IMAGES, true) } @Test diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt index f9c449634e2..c9cc81ae8d8 100644 --- a/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt +++ b/tests/tests/permission3/src/android/permission3/cts/PermissionTest23.kt @@ -247,7 +247,7 @@ class PermissionTest23 : BaseUsePermissionTest() { android.Manifest.permission.CALL_PHONE, android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAMERA, - android.Manifest.permission.READ_EXTERNAL_STORAGE, targetSdk = 23 + android.Manifest.permission.READ_EXTERNAL_STORAGE ) // Don't use UI for granting location and sensor permissions as they show another dialog uiAutomation.grantRuntimePermission( @@ -307,12 +307,12 @@ class PermissionTest23 : BaseUsePermissionTest() { Assume.assumeFalse("other form factors might not support the ask button", isTv || isAutomotive || isWatch) - grantAppPermissions(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, targetSdk = 23) + grantAppPermissions(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) assertAppHasPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, true) assertAppHasPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, true) assertAppHasPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, true) - revokeAppPermissions(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, targetSdk = 23) + revokeAppPermissions(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) SystemUtil.runWithShellPermissionIdentity { val perms = listOf(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, diff --git a/tests/tests/permission4/AndroidTest.xml b/tests/tests/permission4/AndroidTest.xml index 78fe62fdac0..3a60e8a4ed4 100644 --- a/tests/tests/permission4/AndroidTest.xml +++ b/tests/tests/permission4/AndroidTest.xml @@ -34,6 +34,13 @@ <option name="test-file-name" value="CtsAppThatAccessesMicAndCameraPermission.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" /> + <option name="restore-settings" value="true" /> + <option name="disable-device-config-sync" value="true" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.permission4.cts" /> <option name="runtime-hint" value="5m" /> diff --git a/tests/tests/permission5/AndroidTest.xml b/tests/tests/permission5/AndroidTest.xml index 953df0de922..abc0896ca85 100644 --- a/tests/tests/permission5/AndroidTest.xml +++ b/tests/tests/permission5/AndroidTest.xml @@ -33,6 +33,13 @@ <option name="test-file-name" value="CtsPermission5TestCases.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> + <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> + <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" /> + <option name="restore-settings" value="true" /> + <option name="disable-device-config-sync" value="true" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller" > <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="CtsBlamedPermissionApp.apk" /> diff --git a/tests/tests/sdksandbox/webkit/Android.bp b/tests/tests/sdksandbox/webkit/Android.bp index 47af4008a0b..f0ab1430c64 100644 --- a/tests/tests/sdksandbox/webkit/Android.bp +++ b/tests/tests/sdksandbox/webkit/Android.bp @@ -18,6 +18,7 @@ package { android_test { name: "CtsSdkSandboxWebkitTestCases", + resource_dirs: ["res"], defaults: ["cts_defaults"], libs: [ "android.test.runner", diff --git a/tests/tests/sdksandbox/webkit/res/raw/trustedcert.crt b/tests/tests/sdksandbox/webkit/res/raw/trustedcert.crt new file mode 100644 index 00000000000..d9fad3584d0 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/res/raw/trustedcert.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIUP/dGwbAus1Vf8cWLiAnyRs7duGAwDQYJKoZIhvcNAQEL +BQAwJTEjMCEGA1UEAwwaQ3RzV2Via2l0VGVzdENhc2VzLXRydXN0ZWQwHhcNMjEw +MjA1MTkzMTIxWhcNMzEwMjAzMTkzMTIxWjAlMSMwIQYDVQQDDBpDdHNXZWJraXRU +ZXN0Q2FzZXMtdHJ1c3RlZDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALT6mHjIXl4ZCea7eZNOEQ8WXbR/uhimTJG3YUD2l+SC9k+dnrXJPvIrKzDq/HB0 +PO/0vNOBIeLd9CIDWVhg2tZ9J542EJB02Fueotcr30SuTG4lMtuD1Iyd37LZwUEd +3nsFOdh65hwgzuyvBUm86CQCbNdXuj9FysHynh/plBopOTAhQkVWHKgQnKGui3Cu +7h55GFPWxBNvc9ugCee0N+CtKhTj2ngBUd46iGmL3h7gXJOwBKrEkfdZLtz6DW5L +Rv0+LyNcJBu5bIbU/0JK9419vbzcjvVDstgIeZJCXlc4XepPy7ASyNLJNYAe9UHc +97Hw3yxu4VlNaGK1WbbDsOgU2Wvf0j9iGFwuuJch5pnCsJuS+rKSeCUXMz71gwo1 +lplpRNWkQkx8/0hae788M74BlQWJfV795SoAOk/qq+HxqmSv43bTaMn6UOCiBAml +BNHgi5SF3vxlebSnHENRJTAx0JI7H5uXFPQswHYu6IGy23yFeWD+9RLADivzdiYw +YMbeO7289+CTrTX5JKtfNqrF9Q9iqMgU3gaq2t4TKwBiIp/M5q6BLjY1spIHAnc5 +WD8y7b7ymswPUxtjaOBxdzr/dzan0ziQIKfywu6mHDQl2kWwYpFMHwIp2O1wP2Gg +5KS6jDj9LNveV5V1GytuWIxMlyeQ8we13aIe8jURloVLAgMBAAGjbzBtMB0GA1Ud +DgQWBBRZIZS/ttjxMLfPr91mYr9yW/b4YjAfBgNVHSMEGDAWgBRZIZS/ttjxMLfP +r91mYr9yW/b4YjAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9z +dIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAgEAT9c+EnbGK+hpxVlwPiNCk7jWc7zb +6aUnyI+EVHKvMhOuSzFzllW4NZIl0ZWxzVd15LRiLaNoLXCTKWnL5MYA6BZYlT2i +gaKVO6z8ytPfRcq1ITYp75b3N0cD7X28g6GNg7hyi/KEx0X1WS8fb88KC6fl/Sy6 +wdWg1WxPaOCosKvMwLpiFoemJBFIhNGzIghRye6MV7PjMRbb0weEQUNmtsxCtq+e +ARBL+pXznphk3nOgreI0VlIi7imre+w6KfaTP0+UBOKhZvk451kPSHRBv8+lC6tS +EcxqJOH/UKLQNyTzmLCLrdjnkRcwLhzegoskmLWGV4Ca2MVV3d6zGRczFplEi/lW +Sux3Pbga+fh3FL1NqnpDCWgEptq+4mNYQn6G71jVOGw3MQtWEZijG95GPC1Yody6 +/CmNzg7eHY1PluXu73aOvJLjESqK1AxZTgpjbN1vUHg8WeSli3/Zcqn12r3FQSEY +qPV3bfWivq7H9UZqHHb9aONBPRhH1xVKf5ByJNwNgRMD4sdBHtklvF1fKnOs3sZ5 +7RhRWn2mNskAHZsVtBGcPCqzPk8oGCptxaEr2rAotb3kD/3TZc2miZUN+AWfOG+U +QeZLno7U+INDfTQC5D8be9LviYdYK8IkolzHHFcDw0Nyyx5hzj7xNq9T4ENGbjMP +5RiEoWyKwEGZGoY= +-----END CERTIFICATE----- diff --git a/tests/tests/sdksandbox/webkit/res/raw/trustedkey.der b/tests/tests/sdksandbox/webkit/res/raw/trustedkey.der Binary files differnew file mode 100644 index 00000000000..5ac993a4ed1 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/res/raw/trustedkey.der diff --git a/tests/tests/sdksandbox/webkit/res/raw/untrustedcert.crt b/tests/tests/sdksandbox/webkit/res/raw/untrustedcert.crt new file mode 100644 index 00000000000..c75e8938302 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/res/raw/untrustedcert.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFSzCCAzOgAwIBAgIUf5q9s3tlwksxPAbNPire6b8YvQUwDQYJKoZIhvcNAQEL +BQAwJzElMCMGA1UEAwwcQ3RzV2Via2l0VGVzdENhc2VzLXVudHJ1c3RlZDAeFw0y +MTAyMDUxOTMxMjFaFw0zMTAyMDMxOTMxMjFaMCcxJTAjBgNVBAMMHEN0c1dlYmtp +dFRlc3RDYXNlcy11bnRydXN0ZWQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQC5atc0ZDX6R5MIemlOoAwPrjN/DGazzStLE7VCxX8pgK92G7Ur2Attd8C/ +I8c8gvCcOnfF+cvxEe6DSwamLPf/qoCght8RKP8kvEE6OmbjYhL7IEp6wIsP3ER9 +D41wVbbXVOlt2DVDsV/STIoEtQSOW2apT3QIlk65uW6NUyzT94OQKqnXnzToy9/b +j/g0ONWjmMML7TAz0qJrW89yAjuzxOMkx9VFONt+kN8SyidRdGhtFrJWDP6FCzHZ +FtMgMpzEsQTFfDBPwnZDHMIQId5Rs4DxLF6OuTIO5gI94e4fQs0vQtudpItm11IP +m9Nrui+A4A+ySYQ4Qd+ac7NUUw3qBTRhhtVW08gRllIlNpUe2WG3agRd+BybZgPI +KuOPwAhPZyYCUX/TRafwaAWCcdhNVvERHe8KD9NHV/fAf0fqTvsEKzpV6n58W6oo +TrsG45+3oFMc24akGajN4MlcYovOA+dCkKp9/dt+dAqD//oPm79gK98is78jcEcW +Vx+ayAVdMM02YcZhhI7g44HRxHXRVEWMgTckpQZ0Y+5fGfTdvKIzPpFqGZ888TaU +RgJTEcb2lM/GpSdFlTxsd4idLiYfbZDZ2e8LeDnCzgDxhHCaHK6nensgjA6UIGro +wYpA+OF929zojBAHGVZzrK2RWEAmT35YXpAbbuFHRipWHeWe+QIDAQABo28wbTAd +BgNVHQ4EFgQU89I2yAoiDmTOLQHkUpYP4KAZafgwHwYDVR0jBBgwFoAU89I2yAoi +DmTOLQHkUpYP4KAZafgwDwYDVR0TAQH/BAUwAwEB/zAaBgNVHREEEzARgglsb2Nh +bGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAB+AHqtcGsJqORIJAH9OWlmB +3EDiNrYjjeMWcuFx4kWPGWEXjOWf7NmnWCoyL7JhQEDO71U3T/FxLhsuTHgqABh2 +TP3V8yYgsLtosQORLrbTgSMnJ6ApcvFC6A6busp6WGExeuiGvVbFlPwP7oInKkXP +Gb6LPpwp2F6hVitNOCzzTNlZy/77faOoqGI307sFX28XJT+Oj1Zs08AgCEoYkEK0 +vYx7z0qVOvWFTMAgIMBefJBcxLlMmrkL9hyFRZN1y1dir+6zhz7nSnThtYr16tsq +dHU4+F6gfmlerbEbAHX9h0Kx9UY+mdgtU3CywM6xufM4iK2LwE8Wzr5/ND8jnvH8 +2sPdjVMZpPPNPc6M2K7W/IdSrlEOAFopBFvFCLtsFNssp9gNiuEwSE9Ver73xE+S +3uH0y4kfESmJVQeEdviA1qcDuSxLQoTsXJSKJdWaMfOJMVR7yGFiV6Tz89puurPP +5Fprk4RbOcAWLHTVLOnTcwB6cvJ5FUIJEw2UOWFJQp6uQ2KkHXuIvBQjNNSuuTOg +HGrIDhEVV1vbfEmx3X7BKE2svp+xp4o/TM8j5CytWC/D0qVGCnqGNCONyV4uNs7O +/3NzqixCcLDz+B2bzieW3Qjb76t68ZJ7JxvB6c9fiUrlmUcdPaSWKpXonjvlI0pN +A5+Gfe2t0uDpO1MROjkA +-----END CERTIFICATE----- diff --git a/tests/tests/sdksandbox/webkit/res/raw/untrustedkey.der b/tests/tests/sdksandbox/webkit/res/raw/untrustedkey.der Binary files differnew file mode 100644 index 00000000000..134bef87868 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/res/raw/untrustedkey.der diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieManagerTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieManagerTest.java new file mode 100644 index 00000000000..8db9cdf8a51 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieManagerTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.sdksandbox.webkit.cts; + +import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SdkSandboxCookieManagerTest { + @ClassRule + public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = + new KeepSdkSandboxAliveRule("com.android.emptysdkprovider"); + + @Rule + public final WebViewSandboxTestRule sdkTester = + new WebViewSandboxTestRule("android.webkit.cts.CookieManagerTest"); + + @Test + public void testGetInstance() throws Exception { + sdkTester.assertSdkTestRunPasses("testGetInstance"); + } + + @Test + public void testFlush() throws Exception { + sdkTester.assertSdkTestRunPasses("testFlush"); + } + + @Test + public void testAcceptCookie() throws Exception { + sdkTester.assertSdkTestRunPasses("testAcceptCookie"); + } + + @Test + public void testSetCookie() throws Exception { + sdkTester.assertSdkTestRunPasses("testSetCookie"); + } + + @Test + public void testSetCookieNullCallback() throws Exception { + sdkTester.assertSdkTestRunPasses("testSetCookieNullCallback"); + } + + @Test + public void testSetCookieCallback() throws Exception { + sdkTester.assertSdkTestRunPasses("testSetCookieCallback"); + } + + @Test + public void testRemoveCookies() throws Exception { + sdkTester.assertSdkTestRunPasses("testRemoveCookies"); + } + + @Test + public void testRemoveCookiesNullCallback() throws Exception { + sdkTester.assertSdkTestRunPasses("testRemoveCookiesNullCallback"); + } + + @Test + public void testRemoveCookiesCallback() throws Exception { + sdkTester.assertSdkTestRunPasses("testRemoveCookiesCallback"); + } + + @Test + public void testThirdPartyCookie() throws Exception { + sdkTester.assertSdkTestRunPasses("testThirdPartyCookie"); + } + + @Test + public void testSameSiteLaxByDefault() throws Exception { + sdkTester.assertSdkTestRunPasses("testSameSiteLaxByDefault"); + } + + @Test + public void testSameSiteNoneRequiresSecure() throws Exception { + sdkTester.assertSdkTestRunPasses("testSameSiteNoneRequiresSecure"); + } + + @Test + public void testSchemefulSameSite() throws Exception { + sdkTester.assertSdkTestRunPasses("testSchemefulSameSite"); + } + + @Test + public void testb3167208() throws Exception { + sdkTester.assertSdkTestRunPasses("testb3167208"); + } +} diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieTest.java index a99a7066bba..52f4daf9a58 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxCookieTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -42,11 +38,6 @@ public class SdkSandboxCookieTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.CookieTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Presubmit @Test public void testDomain() throws Exception { diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxDateSorterTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxDateSorterTest.java index b563d808133..e83a5248961 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxDateSorterTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxDateSorterTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -43,11 +39,6 @@ public class SdkSandboxDateSorterTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.DateSorterTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testConstructor() throws Exception { sdkTester.assertSdkTestRunPasses("testConstructor"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxHttpAuthHandlerTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxHttpAuthHandlerTest.java index f44bff0f546..05e9a1ff604 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxHttpAuthHandlerTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxHttpAuthHandlerTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -43,11 +39,6 @@ public class SdkSandboxHttpAuthHandlerTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.HttpAuthHandlerTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testProceed() throws Exception { sdkTester.assertSdkTestRunPasses("testProceed"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxPostMessageTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxPostMessageTest.java index c29d806f181..214084a0484 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxPostMessageTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxPostMessageTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -43,11 +39,6 @@ public class SdkSandboxPostMessageTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.PostMessageTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testSimpleMessageToMainFrame() throws Exception { sdkTester.assertSdkTestRunPasses("testSimpleMessageToMainFrame"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxServiceWorkerClientTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxServiceWorkerClientTest.java index c3ee9b05188..39922ede210 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxServiceWorkerClientTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxServiceWorkerClientTest.java @@ -21,10 +21,6 @@ import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -41,11 +37,6 @@ public class SdkSandboxServiceWorkerClientTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.ServiceWorkerClientTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testServiceWorkerClientInterceptCallback() throws Exception { sdkTester.assertSdkTestRunPasses("testServiceWorkerClientInterceptCallback"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxURLUtilTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxURLUtilTest.java index f2de548d944..4e047c73431 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxURLUtilTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxURLUtilTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -43,11 +39,6 @@ public class SdkSandboxURLUtilTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.URLUtilTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testIsAssetUrl() throws Exception { sdkTester.assertSdkTestRunPasses("testIsAssetUrl"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebBackForwardListTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebBackForwardListTest.java index 9940f1c9fe8..7d8c85bcc40 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebBackForwardListTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebBackForwardListTest.java @@ -21,10 +21,6 @@ import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -41,11 +37,6 @@ public class SdkSandboxWebBackForwardListTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.WebBackForwardListTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testGetCurrentItem() throws Exception { sdkTester.assertSdkTestRunPasses("testGetCurrentItem"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebChromeClientTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebChromeClientTest.java new file mode 100644 index 00000000000..95ec8dae855 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebChromeClientTest.java @@ -0,0 +1,95 @@ +/* + * 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.sdksandbox.webkit.cts; + +import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SdkSandboxWebChromeClientTest { + + @ClassRule + public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = + new KeepSdkSandboxAliveRule("com.android.emptysdkprovider"); + + @Rule + public final WebViewSandboxTestRule sdkTester = + new WebViewSandboxTestRule("android.webkit.cts.WebChromeClientTest"); + + @Test + public void testOnProgressChanged() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnProgressChanged"); + } + + @Test + public void testOnReceivedTitle() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedTitle"); + } + + @Test + public void testOnReceivedIcon() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedIcon"); + } + + @Test + public void testWindows() throws Exception { + sdkTester.assertSdkTestRunPasses("testWindows"); + } + + @Test + public void testBlockWindowsSync() throws Exception { + sdkTester.assertSdkTestRunPasses("testBlockWindowsSync"); + } + + @Test + public void testBlockWindowsAsync() throws Exception { + sdkTester.assertSdkTestRunPasses("testBlockWindowsAsync"); + } + + @Test + public void testOnJsAlert() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnJsAlert"); + } + + @Test + public void testOnJsConfirm() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnJsConfirm"); + } + + @Test + public void testOnJsPrompt() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnJsPrompt"); + } + + @Test + public void testOnConsoleMessage() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnConsoleMessage"); + } + + @Test + public void testOnJsBeforeUnloadIsCalled() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnJsBeforeUnloadIsCalled"); + } + +} diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebHistoryItemTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebHistoryItemTest.java index fbfd3c20e78..5eb7225e286 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebHistoryItemTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebHistoryItemTest.java @@ -21,10 +21,6 @@ import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -41,11 +37,6 @@ public class SdkSandboxWebHistoryItemTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.WebHistoryItemTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testWebHistoryItem() throws Exception { sdkTester.assertSdkTestRunPasses("testWebHistoryItem"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebSettingsTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebSettingsTest.java new file mode 100644 index 00000000000..e2112aed33d --- /dev/null +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebSettingsTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.sdksandbox.webkit.cts; + +import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SdkSandboxWebSettingsTest { + @ClassRule + public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = + new KeepSdkSandboxAliveRule("com.android.emptysdkprovider"); + + @Rule + public final WebViewSandboxTestRule sdkTester = + new WebViewSandboxTestRule("android.webkit.cts.WebSettingsTest"); + + @Test + public void testUserAgentString_default() throws Exception { + sdkTester.assertSdkTestRunPasses("testUserAgentString_default"); + } + + @Test + public void testUserAgentStringTest() throws Exception { + sdkTester.assertSdkTestRunPasses("testUserAgentStringTest"); + } + + @Test + public void testAccessUserAgentString() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessUserAgentString"); + } + + @Test + public void testAccessCacheMode_defaultValue() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessCacheMode_defaultValue"); + } + + @Test + public void testAccessCacheMode_cacheElseNetwork() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessCacheMode_cacheElseNetwork"); + } + + @Test + public void testAccessCacheMode_noCache() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessCacheMode_noCache"); + } + + @Test + public void testAccessCacheMode_cacheOnly() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessCacheMode_cacheOnly"); + } + + @Test + public void testAccessCursiveFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessCursiveFontFamily"); + } + + @Test + public void testAccessFantasyFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessFantasyFontFamily"); + } + + @Test + public void testAccessFixedFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessFixedFontFamily"); + } + + @Test + public void testAccessSansSerifFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessSansSerifFontFamily"); + } + + @Test + public void testAccessSerifFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessSerifFontFamily"); + } + + @Test + public void testAccessStandardFontFamily() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessStandardFontFamily"); + } + + @Test + public void testAccessDefaultFontSize() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessDefaultFontSize"); + } + + @Test + public void testAccessDefaultFixedFontSize() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessDefaultFixedFontSize"); + } + + @Test + public void testAccessDefaultTextEncodingName() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessDefaultTextEncodingName"); + } + + @Test + public void testAccessJavaScriptCanOpenWindowsAutomatically() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessJavaScriptCanOpenWindowsAutomatically"); + } + + @Test + public void testAccessJavaScriptEnabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessJavaScriptEnabled"); + } + + @Test + public void testAccessLayoutAlgorithm() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessLayoutAlgorithm"); + } + + @Test + public void testAccessMinimumFontSize() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessMinimumFontSize"); + } + + @Test + public void testAccessMinimumLogicalFontSize() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessMinimumLogicalFontSize"); + } + + @Test + public void testAccessPluginsEnabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessPluginsEnabled"); + } + + @Test + public void testOffscreenPreRaster() throws Exception { + sdkTester.assertSdkTestRunPasses("testOffscreenPreRaster"); + } + + @Test + public void testAccessPluginsPath() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessPluginsPath"); + } + + @Test + public void testAccessTextSize() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessTextSize"); + } + + @Test + public void testAccessUseDoubleTree() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessUseDoubleTree"); + } + + @Test + public void testAccessUseWideViewPort() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessUseWideViewPort"); + } + + @Test + public void testSetNeedInitialFocus() throws Exception { + sdkTester.assertSdkTestRunPasses("testSetNeedInitialFocus"); + } + + @Test + public void testSetRenderPriority() throws Exception { + sdkTester.assertSdkTestRunPasses("testSetRenderPriority"); + } + + @Test + public void testAccessSupportMultipleWindows() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessSupportMultipleWindows"); + } + + @Test + public void testAccessSupportZoom() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessSupportZoom"); + } + + @Test + public void testAccessBuiltInZoomControls() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessBuiltInZoomControls"); + } + + @Test + public void testAppCacheDisabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testAppCacheDisabled"); + } + + @Test + public void testAppCacheEnabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testAppCacheEnabled"); + } + + @Test + public void testDatabaseDisabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testDatabaseDisabled"); + } + + @Test + public void testDisabledActionModeMenuItems() throws Exception { + sdkTester.assertSdkTestRunPasses("testDisabledActionModeMenuItems"); + } + + @Test + public void testLoadsImagesAutomatically_default() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadsImagesAutomatically_default"); + } + + @Test + public void testLoadsImagesAutomatically_httpImagesLoaded() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadsImagesAutomatically_httpImagesLoaded"); + } + + @Test + public void testLoadsImagesAutomatically_dataUriImagesLoaded() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadsImagesAutomatically_dataUriImagesLoaded"); + } + + @Test + public void testLoadsImagesAutomatically_blockLoadingImages() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadsImagesAutomatically_blockLoadingImages"); + } + + @Test + public void testLoadsImagesAutomatically_loadImagesWithoutReload() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadsImagesAutomatically_loadImagesWithoutReload"); + } + + @Test + public void testBlockNetworkImage() throws Exception { + sdkTester.assertSdkTestRunPasses("testBlockNetworkImage"); + } + + @Test + public void testBlockNetworkLoads() throws Exception { + sdkTester.assertSdkTestRunPasses("testBlockNetworkLoads"); + } + + @Test + public void testIframesWhenAccessFromFileURLsDisabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testIframesWhenAccessFromFileURLsDisabled"); + } + + @Test + public void testXHRWhenAccessFromFileURLsEnabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testXHRWhenAccessFromFileURLsEnabled"); + } + + @Test + public void testXHRWhenAccessFromFileURLsDisabled() throws Exception { + sdkTester.assertSdkTestRunPasses("testXHRWhenAccessFromFileURLsDisabled"); + } + + @Test + public void testAllowMixedMode() throws Exception { + sdkTester.assertSdkTestRunPasses("testAllowMixedMode"); + } + + @Test + public void testEnableSafeBrowsing() throws Exception { + sdkTester.assertSdkTestRunPasses("testEnableSafeBrowsing"); + } +} diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewClientTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewClientTest.java new file mode 100644 index 00000000000..68b68ba8977 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewClientTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.sdksandbox.webkit.cts; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.MediumTest; + +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SdkSandboxWebViewClientTest { + // TODO(b/260196711): IME does not currently work correctly in the SDK RUntime. We should enable + // impacted tests once this is fixed. + // This prevents some tests from running. + private static final boolean CAN_INJECT_KEY_EVENTS = false; + + // TODO(b/266051278): Uncomment this when we work out why preserving + // the SDK sandbox manager between tests cases {@link testOnRenderProcessGone} + // to fail. + // + // @ClassRule + // public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = + // new KeepSdkSandboxAliveRule("com.android.emptysdkprovider"); + + @Rule + public final WebViewSandboxTestRule sdkTester = + new WebViewSandboxTestRule("android.webkit.cts.WebViewClientTest"); + + @Test + public void testShouldOverrideUrlLoadingDefault() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldOverrideUrlLoadingDefault"); + } + + @Test + public void testShouldOverrideUrlLoading() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldOverrideUrlLoading"); + } + + @Test + public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldOverrideUrlLoadingOnCreateWindow"); + } + + @Test + public void testLoadPage() throws Exception { + sdkTester.assertSdkTestRunPasses("testLoadPage"); + } + + @Test + public void testOnReceivedLoginRequest() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedLoginRequest"); + } + + @Test + public void testOnReceivedError() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedError"); + } + + @Test + public void testOnReceivedErrorForSubresource() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedErrorForSubresource"); + } + + @Test + public void testOnReceivedHttpError() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedHttpError"); + } + + @Test + public void testOnFormResubmission() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnFormResubmission"); + } + + @Test + public void testDoUpdateVisitedHistory() throws Exception { + sdkTester.assertSdkTestRunPasses("testDoUpdateVisitedHistory"); + } + + @Test + public void testOnReceivedHttpAuthRequest() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnReceivedHttpAuthRequest"); + } + + @Test + public void testShouldOverrideKeyEvent() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldOverrideKeyEvent"); + } + + @Test + public void testOnUnhandledKeyEvent() throws Exception { + Assume.assumeTrue(CAN_INJECT_KEY_EVENTS); + sdkTester.assertSdkTestRunPasses("testOnUnhandledKeyEvent"); + } + + @Test + public void testOnScaleChanged() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnScaleChanged"); + } + + @Test + public void testShouldInterceptRequestParams() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldInterceptRequestParams"); + } + + @Test + public void testShouldInterceptRequestResponse() throws Exception { + sdkTester.assertSdkTestRunPasses("testShouldInterceptRequestResponse"); + } + + @Test + public void testOnRenderProcessGoneDefault() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnRenderProcessGoneDefault"); + } + + @Test + public void testOnRenderProcessGone() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnRenderProcessGone"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingHitBackToSafety() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingHitBackToSafety"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingHitProceed() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingHitProceed"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingMalwareCode() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingMalwareCode"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingPhishingCode() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingPhishingCode"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingUnwantedSoftwareCode() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingUnwantedSoftwareCode"); + } + + // TODO(crbug/1245351): Remove @FlakyTest once bug fixed + @FlakyTest + @Test + public void testOnSafeBrowsingBillingCode() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnSafeBrowsingBillingCode"); + } + + @Test + public void testOnPageCommitVisibleCalled() throws Exception { + sdkTester.assertSdkTestRunPasses("testOnPageCommitVisibleCalled"); + } +} diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewSslTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewSslTest.java index b5c2bf8393c..ba5975e7d08 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewSslTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewSslTest.java @@ -22,10 +22,6 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -42,11 +38,6 @@ public class SdkSandboxWebViewSslTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.WebViewSslTest"); - @Before - public void checkAssumptions() throws Exception { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test @MediumTest public void testInsecureSiteClearsCertificate() throws Exception { diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTest.java index 14e6592641e..e6de7e8bed5 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTest.java @@ -23,10 +23,7 @@ import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -36,10 +33,10 @@ import org.junit.runner.RunWith; @AppModeFull @RunWith(AndroidJUnit4.class) public class SdkSandboxWebViewTest { - // TODO(b/260196711): We are not able to inject input events - // from the SDK Runtime.SdkSandbox + // TODO(b/230340812): IME does not currently work correctly in the SDK RUntime. We should enable + // impacted tests once this is fixed. // This prevents some tests from running. - private static final boolean CAN_INJECT_INPUT_EVENTS = false; + private static final boolean CAN_INJECT_KEY_EVENTS = false; @ClassRule public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = @@ -49,11 +46,6 @@ public class SdkSandboxWebViewTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.WebViewTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testConstructor() throws Exception { sdkTester.assertSdkTestRunPasses("testConstructor"); @@ -394,19 +386,18 @@ public class SdkSandboxWebViewTest { @Test public void testRequestFocusNodeHref() throws Exception { - Assume.assumeTrue(CAN_INJECT_INPUT_EVENTS); + Assume.assumeTrue(CAN_INJECT_KEY_EVENTS); sdkTester.assertSdkTestRunPasses("testRequestFocusNodeHref"); } @Test public void testRequestImageRef() throws Exception { - Assume.assumeTrue(CAN_INJECT_INPUT_EVENTS); sdkTester.assertSdkTestRunPasses("testRequestImageRef"); } @Test public void testGetHitTestResult() throws Exception { - Assume.assumeTrue(CAN_INJECT_INPUT_EVENTS); + Assume.assumeTrue(CAN_INJECT_KEY_EVENTS); sdkTester.assertSdkTestRunPasses("testGetHitTestResult"); } } diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTransportTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTransportTest.java new file mode 100644 index 00000000000..a4db755e434 --- /dev/null +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewTransportTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.sdksandbox.webkit.cts; + +import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.MediumTest; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SdkSandboxWebViewTransportTest { + @ClassRule + public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup = + new KeepSdkSandboxAliveRule("com.android.emptysdkprovider"); + + @Rule + public final WebViewSandboxTestRule sdkTester = + new WebViewSandboxTestRule("android.webkit.cts.WebViewTransportTest"); + + @Test + public void testAccessWebView() throws Exception { + sdkTester.assertSdkTestRunPasses("testAccessWebView"); + } +} diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewZoomTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewZoomTest.java index 9f13fed16d8..4afee9ca31d 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewZoomTest.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkSandboxWebViewZoomTest.java @@ -20,10 +20,6 @@ import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import com.android.compatibility.common.util.NullWebViewUtils; - -import org.junit.Assume; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -41,11 +37,6 @@ public class SdkSandboxWebViewZoomTest { public final WebViewSandboxTestRule sdkTester = new WebViewSandboxTestRule("android.webkit.cts.WebViewZoomTest"); - @Before - public void setUp() { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - } - @Test public void testZoomIn() throws Exception { sdkTester.assertSdkTestRunPasses("testZoomIn"); diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/WebViewSandboxTestRule.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/WebViewSandboxTestRule.java index c9d641fdee6..433b5cecf5a 100644 --- a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/WebViewSandboxTestRule.java +++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/WebViewSandboxTestRule.java @@ -24,6 +24,12 @@ import android.webkit.cts.SharedWebViewTestEnvironment; import androidx.test.core.app.ApplicationProvider; +import com.android.compatibility.common.util.NullWebViewUtils; + +import org.junit.Assume; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + /** * This rule is used to invoke webview tests inside a test sdk. * This rule is a wrapper for using the @@ -34,10 +40,11 @@ import androidx.test.core.app.ApplicationProvider; public class WebViewSandboxTestRule extends SdkSandboxScenarioRule { public WebViewSandboxTestRule(String webViewTestClassName) { - super("com.android.cts.sdk.webviewsandboxtest", + super( + "com.android.cts.sdk.webviewsandboxtest", getSetupParams(webViewTestClassName), SharedWebViewTestEnvironment.createHostAppInvoker( - ApplicationProvider.getApplicationContext()), + ApplicationProvider.getApplicationContext(), true), ENABLE_LIFE_CYCLE_ANNOTATIONS); } @@ -46,4 +53,11 @@ public class WebViewSandboxTestRule extends SdkSandboxScenarioRule { params.putString(SharedWebViewTest.WEB_VIEW_TEST_CLASS_NAME, webViewTestClassName); return params; } + + @Override + public Statement apply(final Statement base, final Description description) { + // This will prevent shared webview tests from running if a WebView provider does not exist. + Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); + return super.apply(base, description); + } } diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml index 7627600c97c..5487fb43bde 100644 --- a/tests/tests/security/AndroidManifest.xml +++ b/tests/tests/security/AndroidManifest.xml @@ -27,6 +27,7 @@ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <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"/> @@ -217,6 +218,11 @@ <activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" /> <activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" /> + <activity android:name="android.security.cts.PackageInstallerTest$BackgroundLaunchActivity" + android:exported="true" /> + <service android:name="android.security.cts.TestForegroundService" + android:exported="true" /> + <provider android:name="android.security.cts.CVE_2022_20358.PocContentProvider" android:authorities="android.security.cts.CVE_2022_20358.provider" android:enabled="true" diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20611.java b/tests/tests/security/src/android/security/cts/CVE_2022_20611.java new file mode 100644 index 00000000000..02526f4b3f9 --- /dev/null +++ b/tests/tests/security/src/android/security/cts/CVE_2022_20611.java @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR 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 com.android.compatibility.common.util.ShellUtils.runShellCommand; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.platform.test.annotations.AsbSecurityTest; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.compatibility.common.util.SystemUtil; +import com.android.sts.common.util.StsExtraBusinessLogicTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith(AndroidJUnit4.class) +public class CVE_2022_20611 extends StsExtraBusinessLogicTestCase { + /** + * CVE-2022-20611 + */ + @AsbSecurityTest(cveBugId = 242996180) + @Test + public void testPocCVE_2022_20611() throws Exception { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + int provisioningAppId = context.getResources().getIdentifier( + "config_deviceProvisioningPackage", "string", "android"); + assumeTrue("config_deviceProvisioningPackage not found.", provisioningAppId > 0); + + String protectedPkg = context.getResources().getString(provisioningAppId); + assumeFalse("config_deviceProvisioningPackage is not set", protectedPkg.isEmpty()); + + String res = runShellCommand("pm list packages " + protectedPkg); + assumeTrue(protectedPkg + " is not installed.", res.contains(protectedPkg)); + + res = runShellCommand("pm uninstall -k --user 0 " + protectedPkg); + if (!res.contains("DELETE_FAILED_INTERNAL_ERROR")) { + runShellCommand("pm install-existing --user 0 " + protectedPkg); + fail( + "Protected package '" + protectedPkg + "' could be uninstalled. " + + "Vulnerable to b/242994180."); + } + } +} diff --git a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java index ddea21385d8..43124ecd847 100644 --- a/tests/tests/security/src/android/security/cts/PackageInstallerTest.java +++ b/tests/tests/security/src/android/security/cts/PackageInstallerTest.java @@ -16,25 +16,46 @@ package android.security.cts; +import static android.content.Intent.EXTRA_REMOTE_CALLBACK; + import android.Manifest; +import android.app.Activity; +import android.app.Instrumentation; +import android.app.Instrumentation.ActivityMonitor; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.ConditionVariable; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.RemoteCallback; import android.platform.test.annotations.AppModeFull; import android.platform.test.annotations.AsbSecurityTest; +import android.provider.Settings; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.compatibility.common.util.SystemUtil; 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.AfterClass; import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; @RunWith(AndroidJUnit4.class) @AppModeFull @@ -42,10 +63,41 @@ public class PackageInstallerTest extends StsExtraBusinessLogicTestCase { private static final String TEST_APP_NAME = "android.security.cts.packageinstallertestapp"; + private static final String KEY_ERROR = "key_error"; + private static final String ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER = TEST_APP_NAME + + ".action.COMMIT_WITH_ACTIVITY_INTENT_SENDER"; + private static final String ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER = TEST_APP_NAME + + ".action.COMMIT_WITH_FG_SERVICE_INTENT_SENDER"; + + static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15); + private static final TestApp TEST_APP = new TestApp( "PackageInstallerTestApp", TEST_APP_NAME, 1, /*isApex*/ false, "PackageInstallerTestApp.apk"); + private static Context sContext = InstrumentationRegistry.getInstrumentation().getContext(); + private static HandlerThread sResponseThread; + private static Handler sHandler; + + private static final ComponentName BACKGROUND_RECEIVER_COMPONENT_NAME = + ComponentName.createRelative(TEST_APP_NAME, ".BackgroundReceiver"); + private static final ComponentName BACKGROUND_LAUNCH_ACTIVITY_COMPONENT_NAME = + new ComponentName(sContext, BackgroundLaunchActivity.class); + private static final ComponentName FOREGROUND_SERVICE_COMPONENT_NAME = + new ComponentName(sContext, TestForegroundService.class); + + @BeforeClass + public static void onBeforeClass() { + sResponseThread = new HandlerThread("response"); + sResponseThread.start(); + sHandler = new Handler(sResponseThread.getLooper()); + } + + @AfterClass + public static void onAfterClass() { + sResponseThread.quit(); + } + @Before public void setUp() { InstrumentationRegistry @@ -74,4 +126,87 @@ public class PackageInstallerTest extends StsExtraBusinessLogicTestCase { Assert.assertNotNull("Did not receive broadcast", packageName); Assert.assertEquals(TEST_APP_NAME, packageName); } + + @Test + @AsbSecurityTest(cveBugId = 230492955) + public void commitSessionInBackground_withActivityIntentSender_doesNotLaunchActivity() + throws Exception { + Install.single(TEST_APP).commit(); + // An activity with the system uid in the foreground is necessary to this test. + goToSettings(); + final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + final ActivityMonitor monitor = instrumentation.addMonitor( + BackgroundLaunchActivity.class.getName(), null /* result */, false /* block */); + try { + sendActionToBackgroundReceiver( + ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER, + BACKGROUND_LAUNCH_ACTIVITY_COMPONENT_NAME); + + final Activity activity = monitor.waitForActivityWithTimeout(DEFAULT_TIMEOUT_MS); + if (activity != null) { + instrumentation.runOnMainSync(() -> activity.finish()); + } + Assert.assertNull(activity); + } finally { + instrumentation.removeMonitor(monitor); + } + } + + @Test + @AsbSecurityTest(cveBugId = 243377226) + public void commitSessionInBackground_withForegroundServiceIntentSender_doesNotStartService() + throws Exception { + Install.single(TEST_APP).commit(); + // An activity with the system uid in the foreground is necessary to this test. + goToSettings(); + + sendActionToBackgroundReceiver( + ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER, FOREGROUND_SERVICE_COMPONENT_NAME); + + final Service service = + TestForegroundService.waitFor(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + if (service != null) { + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> service.stopSelf()); + } + Assert.assertNull(service); + } + + private void goToSettings() { + SystemUtil.runShellCommand( + "am start -W --user current -a " + Settings.ACTION_SETTINGS); + } + + private Bundle sendActionToBackgroundReceiver(String action, ComponentName statusReceiver) + throws Exception { + final Intent intent = new Intent(action) + .setComponent(BACKGROUND_RECEIVER_COMPONENT_NAME); + if (statusReceiver != null) { + intent.putExtra(Intent.EXTRA_COMPONENT_NAME, statusReceiver); + } + final ConditionVariable latch = new ConditionVariable(); + final AtomicReference<Bundle> resultReference = new AtomicReference<>(); + final RemoteCallback remoteCallback = new RemoteCallback( + bundle -> { + resultReference.set(bundle); + latch.open(); + }, + sHandler); + intent.putExtra(EXTRA_REMOTE_CALLBACK, remoteCallback); + sContext.sendBroadcast(intent); + + if (!latch.block(DEFAULT_TIMEOUT_MS)) { + throw new TimeoutException( + "Latch timed out while awaiting a response from background receiver"); + } + final Bundle bundle = resultReference.get(); + if (bundle != null && bundle.containsKey(KEY_ERROR)) { + throw Objects.requireNonNull(bundle.getSerializable(KEY_ERROR, Exception.class)); + } + return bundle; + } + + // An activity to receive status of a committed session + public static class BackgroundLaunchActivity extends Activity { + } } diff --git a/tests/tests/security/src/android/security/cts/TestForegroundService.java b/tests/tests/security/src/android/security/cts/TestForegroundService.java new file mode 100644 index 00000000000..b09a925c01d --- /dev/null +++ b/tests/tests/security/src/android/security/cts/TestForegroundService.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR 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.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; + +import org.junit.Assert; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class TestForegroundService extends Service { + private static BlockingQueue<Service> sQueue = new LinkedBlockingQueue<>(); + + private static final int FGS_NOTIFICATION_ID = 1; + private static final String NOTIFICATION_CHANNEL_ID = + TestForegroundService.class.getSimpleName(); + + @Override + public void onCreate() { + createNotificationChannelId(this, NOTIFICATION_CHANNEL_ID); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // When this service is started, make it a foreground service + final Notification.Builder builder = + new Notification.Builder(this, NOTIFICATION_CHANNEL_ID) + .setSmallIcon(android.R.drawable.btn_star) + .setContentTitle(NOTIFICATION_CHANNEL_ID) + .setContentText(TestForegroundService.class.getName()); + startForeground(FGS_NOTIFICATION_ID, builder.build()); + + try { + sQueue.put(this); + } catch (InterruptedException e) { + Assert.fail(e.toString()); + } + return Service.START_NOT_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + /** Create a notification channel. */ + private static void createNotificationChannelId(Context context, String id) { + final NotificationManager nm = + context.getSystemService(NotificationManager.class); + final CharSequence name = id; + final String description = TestForegroundService.class.getName(); + final int importance = NotificationManager.IMPORTANCE_DEFAULT; + final NotificationChannel channel = new NotificationChannel( + NOTIFICATION_CHANNEL_ID, name, importance); + channel.setDescription(description); + nm.createNotificationChannel(channel); + } + + /** Wait until the service is started */ + public static Service waitFor(long timeout, TimeUnit unit) + throws InterruptedException { + return sQueue.poll(timeout, unit); + } +} diff --git a/tests/tests/security/testdata/packageinstallertestapp.xml b/tests/tests/security/testdata/packageinstallertestapp.xml index 5e6e066b3af..ad39db564ae 100644 --- a/tests/tests/security/testdata/packageinstallertestapp.xml +++ b/tests/tests/security/testdata/packageinstallertestapp.xml @@ -34,5 +34,6 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + <receiver android:name=".BackgroundReceiver" android:exported="true" /> </application> </manifest> diff --git a/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java b/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java new file mode 100644 index 00000000000..8997082db52 --- /dev/null +++ b/tests/tests/security/testdata/src/android/security/cts/packageinstallertestapp/BackgroundReceiver.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR 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.packageinstallertestapp; + +import static android.content.Intent.EXTRA_COMPONENT_NAME; +import static android.content.Intent.EXTRA_REMOTE_CALLBACK; +import static android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.Session; +import android.content.pm.PackageInstaller.SessionParams; +import android.os.Bundle; +import android.os.RemoteCallback; + +import java.io.IOException; +import java.util.List; + +/** + * A receiver to invoke APIs in the background. + */ +public class BackgroundReceiver extends BroadcastReceiver { + private static final String PKG_NAME = "android.security.cts.packageinstallertestapp"; + private static final String KEY_ERROR = "key_error"; + private static final String ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER = PKG_NAME + + ".action.COMMIT_WITH_ACTIVITY_INTENT_SENDER"; + private static final String ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER = PKG_NAME + + ".action.COMMIT_WITH_FG_SERVICE_INTENT_SENDER"; + + @Override + public void onReceive(Context context, Intent intent) { + final RemoteCallback remoteCallback = intent.getParcelableExtra(EXTRA_REMOTE_CALLBACK, + RemoteCallback.class); + final ComponentName statusReceiver = intent.getParcelableExtra( + EXTRA_COMPONENT_NAME, ComponentName.class); + final String action = intent.getAction(); + + if (!isAppInBackground(context)) { + sendError(remoteCallback, + new IllegalStateException("App is not in background")); + return; + } + try { + if (action.equals(ACTION_COMMIT_WITH_ACTIVITY_INTENT_SENDER)) { + final IntentSender intentSender = PendingIntent.getActivity(context, + 0 /* requestCode */, + new Intent().setComponent(statusReceiver), + PendingIntent.FLAG_IMMUTABLE) + .getIntentSender(); + sendInstallCommit(context, remoteCallback, intentSender); + } else if (action.equals(ACTION_COMMIT_WITH_FG_SERVICE_INTENT_SENDER)) { + final IntentSender intentSender = PendingIntent.getForegroundService(context, + 0 /* requestCode */, + new Intent().setComponent(statusReceiver), + PendingIntent.FLAG_IMMUTABLE) + .getIntentSender(); + sendInstallCommit(context, remoteCallback, intentSender); + } else { + sendError(remoteCallback, + new IllegalArgumentException("Unknown action: " + action)); + } + } catch (Throwable e) { + sendError(remoteCallback, e); + } + } + + private static boolean isAppInBackground(Context context) { + final ActivityManager activityManager = context.getSystemService(ActivityManager.class); + final List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); + final String packageName = context.getPackageName(); + final RunningAppProcessInfo appInfo = appProcesses.stream() + .filter(app -> app.processName.equals(packageName)) + .findAny().orElse(null); + if (appInfo != null + && appInfo.importance >= RunningAppProcessInfo.IMPORTANCE_SERVICE) { + return true; + } + return false; + } + + private static void sendInstallCommit(Context context, RemoteCallback remoteCallback, + IntentSender intentSender) throws IOException { + final PackageInstaller packageInstaller = + context.getPackageManager().getPackageInstaller(); + final int sessionId = packageInstaller.createSession( + new SessionParams(MODE_FULL_INSTALL)); + final Session session = packageInstaller.openSession(sessionId); + session.commit(intentSender); + sendSuccess(remoteCallback); + } + + private static void sendError(RemoteCallback remoteCallback, Throwable failure) { + Bundle result = new Bundle(); + result.putSerializable(KEY_ERROR, failure); + remoteCallback.sendResult(result); + } + + private static void sendSuccess(RemoteCallback remoteCallback) { + Bundle result = new Bundle(); + remoteCallback.sendResult(result); + } +} diff --git a/tests/tests/settings/src/android/settings/cts/TetherProvisioningCarrierDialogActivityTest.java b/tests/tests/settings/src/android/settings/cts/TetherProvisioningCarrierDialogActivityTest.java index c47ba7a9a9e..40d2b8b4d17 100644 --- a/tests/tests/settings/src/android/settings/cts/TetherProvisioningCarrierDialogActivityTest.java +++ b/tests/tests/settings/src/android/settings/cts/TetherProvisioningCarrierDialogActivityTest.java @@ -16,6 +16,7 @@ package android.settings.cts; +import static org.junit.Assume.assumeFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -44,6 +45,8 @@ public class TetherProvisioningCarrierDialogActivityTest { final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); + assumeFalse( + "Skipping test: Tethering is not supported in Wear OS", isWatch()); } @Test @@ -54,4 +57,9 @@ public class TetherProvisioningCarrierDialogActivityTest { intent, PackageManager.MATCH_DEFAULT_ONLY); assertTrue(ri != null); } + + private boolean isWatch() { + return InstrumentationRegistry.getTargetContext() + .getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); + } } diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml index 1b1d48ea3a1..57d09e7bec8 100644 --- a/tests/tests/telecom/AndroidManifest.xml +++ b/tests/tests/telecom/AndroidManifest.xml @@ -87,6 +87,15 @@ </intent-filter> </service> + <service android:name=".NullBindingCallScreeningService" + android:permission="android.permission.BIND_SCREENING_SERVICE" + android:enabled="false" + android:exported="true"> + <intent-filter> + <action android:name="android.telecom.CallScreeningService"/> + </intent-filter> + </service> + <service android:name="android.telecom.cts.MockInCallService" android:permission="android.permission.BIND_INCALL_SERVICE" android:exported="true"> diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java index 439b37790d9..dbdf8518481 100644 --- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java +++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java @@ -89,6 +89,7 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { public static final int FLAG_REGISTER = 0x1; public static final int FLAG_ENABLE = 0x2; public static final int FLAG_SET_DEFAULT = 0x4; + public static final int FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME = 0x8; // Don't accidently use emergency number. private static int sCounter = 5553638; @@ -360,7 +361,12 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { CtsConnectionService.setUp(this.connectionService); if ((flags & FLAG_REGISTER) != 0) { - mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT); + if ((flags & FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME) != 0) { + mTelecomManager.registerPhoneAccount( + TestUtils.TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME); + } else { + mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT); + } } if ((flags & FLAG_ENABLE) != 0) { TestUtils.enablePhoneAccount(getInstrumentation(), TestUtils.TEST_PHONE_ACCOUNT_HANDLE); @@ -723,6 +729,29 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { } /** + * Verifies that a call was not placed + */ + void placeAndVerifyNoCall(Bundle extras) { + assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); + placeNewCallWithPhoneAccount(extras, 0); + + try { + if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, + TimeUnit.SECONDS)) { + } + } catch (InterruptedException e) { + Log.i(TAG, "Test interrupted!"); + } + + // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall) + // complete successfully + TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); + TestUtils.waitOnAllHandlers(getInstrumentation()); + + assertNull("Service should be null since call should not have been placed", + mInCallCallbacks.getService()); + } + /** * Puts Telecom in a state where there is an active call provided by the * {@link CtsConnectionService} which can be tested. */ @@ -856,6 +885,21 @@ public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { return null; } + void verifyNoConnectionForOutgoingCall() { + try { + if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, + TimeUnit.MILLISECONDS)) { + //fail("No outgoing call connection requested by Telecom"); + } + } catch (InterruptedException e) { + Log.i(TAG, "Test interrupted!"); + } + + assertThat("Telecom should not create outgoing connection for outgoing call", + connectionService.outgoingConnections.size(), equalTo(0)); + return; + } + MockConnection verifyConnectionForIncomingCall() { // Assuming only 1 connection present return verifyConnectionForIncomingCall(0); diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.java new file mode 100644 index 00000000000..6b6e5ed9718 --- /dev/null +++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningService.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.telecom.cts; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.IBinder; +import android.telecom.Call; +import android.telecom.CallScreeningService; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; + +/** + * Provides a minimal CTS-test implementation of {@link CallScreeningService}. + * This emulates an implementation of {@link CallScreeningService} that returns a null binding. + * This is used to test null binding cases to ensure we unbind the service when a null binding is + * received from onBind. + */ +public class NullBindingCallScreeningService extends CallScreeningService { + private static final String TAG = NullBindingCallScreeningService.class.getSimpleName(); + public static CountDownLatch sBindLatch = new CountDownLatch(1); + public static CountDownLatch sUnbindLatch = new CountDownLatch(1); + + @Override + public IBinder onBind(Intent intent) { + Log.i(TAG, "onBind: returning null service"); + sUnbindLatch = new CountDownLatch(1); + sBindLatch.countDown(); + return null; + } + + @Override + public boolean onUnbind(Intent intent) { + Log.i(TAG, "onUnbind: unbinding service"); + sBindLatch = new CountDownLatch(1); + sUnbindLatch.countDown(); + return false; + } + + @Override + public void onScreenCall(Call.Details callDetails) { + Log.i(TAG, "onScreenCall"); + } + + public static void resetBindLatches() { + sBindLatch = new CountDownLatch(1); + sUnbindLatch = new CountDownLatch(1); + } + + public static void enableNullBindingCallScreeningService(Context context) { + ComponentName componentName = new ComponentName(context, + NullBindingCallScreeningService.class); + context.getPackageManager().setComponentEnabledSetting(componentName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + } + + public static void disableNullBindingCallScreeningService(Context context) { + ComponentName componentName = new ComponentName(context, + NullBindingCallScreeningService.class); + context.getPackageManager().setComponentEnabledSetting(componentName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } +} diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java new file mode 100644 index 00000000000..b88643af46d --- /dev/null +++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallScreeningServiceTest.java @@ -0,0 +1,145 @@ +/* + * 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.telecom.cts; + +import static android.telecom.cts.TestUtils.waitOnAllHandlers; + +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import android.app.role.RoleManager; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.os.Process; +import android.os.UserHandle; +import android.telecom.TelecomManager; + +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class NullBindingCallScreeningServiceTest extends BaseTelecomTestWithMockServices { + private static final int ASYNC_TIMEOUT = 10000; + private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING; + private static final Uri TEST_OUTGOING_NUMBER = Uri.fromParts("tel", "6505551212", null); + + private RoleManager mRoleManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (!mShouldTestTelecom) { + return; + } + NullBindingCallScreeningService.enableNullBindingCallScreeningService(mContext); + mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE); + setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE); + // Ensure NullBindingCallScreeningService pkg holds the call screening role. + addRoleHolder(ROLE_CALL_SCREENING, + NullBindingCallScreeningService.class.getPackage().getName()); + NullBindingCallScreeningService.resetBindLatches(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (!mShouldTestTelecom) { + return; + } + // Remove the app from the screening role. + removeRoleHolder(ROLE_CALL_SCREENING, + NullBindingCallScreeningService.class.getPackage().getName()); + NullBindingCallScreeningService.disableNullBindingCallScreeningService(mContext); + } + + public void testNullBindingOnIncomingCall() throws Exception { + Uri testNumber = createRandomTestNumber(); + Bundle extras = new Bundle(); + extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, testNumber); + + // Verify that binding latch counts are reset for testing + assertBindLatchInit(); + // Add a new incoming call + mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras); + // Assert unbind after onBind return a null service + assertBindLatchCountDown(); + // Wait until the new incoming call is processed. Needed for proper tear down. + waitOnAllHandlers(getInstrumentation()); + } + + public void testNullBindingOnOutgoingCall() throws Exception { + Uri testNumber = createRandomTestNumber(); + Bundle extras = new Bundle(); + extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER); + + // Verify that binding latch counts are reset for testing + assertBindLatchInit(); + // Create a new outgoing call. + mTelecomManager.placeCall(testNumber, extras); + // Assert unbind after onBind return a null service + assertBindLatchCountDown(); + } + + private void assertBindLatchInit() { + assertTrue(NullBindingCallScreeningService.sUnbindLatch.getCount() == 1); + assertTrue(NullBindingCallScreeningService.sBindLatch.getCount() == 1); + } + + private void assertBindLatchCountDown() { + assertTrue(TestUtils.waitForLatchCountDown(NullBindingCallScreeningService.sBindLatch)); + assertTrue(TestUtils.waitForLatchCountDown(NullBindingCallScreeningService.sUnbindLatch)); + } + + private void addRoleHolder(String roleName, String packageName) + throws Exception { + UserHandle user = Process.myUserHandle(); + Executor executor = mContext.getMainExecutor(); + LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1); + + runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName, + packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor, + successful -> { + try { + queue.put(successful); + } catch (InterruptedException e) { + e.printStackTrace(); + } + })); + boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); + assertTrue(result); + } + + private void removeRoleHolder(String roleName, String packageName) + throws Exception { + UserHandle user = Process.myUserHandle(); + Executor executor = mContext.getMainExecutor(); + LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1); + + runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName, + packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor, + successful -> { + try { + queue.put(successful); + } catch (InterruptedException e) { + e.printStackTrace(); + } + })); + boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS); + assertTrue(result); + } +} + diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java index 5074ab9834d..90e11d1c6c4 100644 --- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java +++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java @@ -19,10 +19,15 @@ package android.telecom.cts; import static android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT; import static android.telephony.TelephonyManager.CALL_STATE_RINGING; +import android.content.ContentValues; import android.content.Context; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; +import android.provider.Contacts; +import android.provider.ContactsContract; import android.telecom.Call; import android.telecom.CallAudioState; import android.telecom.Connection; @@ -33,6 +38,7 @@ import android.telephony.emergency.EmergencyNumber; import com.android.compatibility.common.util.SystemUtil; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -48,18 +54,53 @@ public class OutgoingCallTest extends BaseTelecomTestWithMockServices { private static final String TEST_EMERGENCY_NUMBER = "9998887776655443210"; + Uri mPersonRecord = null; + Uri mPhoneRecord = null; + private final static String TEST_PHONE_NUMBER = "+18005552871"; + @Override protected void setUp() throws Exception { super.setUp(); NewOutgoingCallBroadcastReceiver.reset(); if (mShouldTestTelecom) { - setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE); + setupConnectionService(null, + FLAG_REGISTER | FLAG_ENABLE | FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME); + + try { + // Add a test contact + ContentResolver cr = getInstrumentation().getTargetContext().getContentResolver(); + mPersonRecord = null; + mPhoneRecord = null; + + // insert a contact with phone number + ContentValues values = new ContentValues(); + values.put(Contacts.People.NAME, "CTS test contact"); + mPersonRecord = cr.insert(Contacts.People.CONTENT_URI, values); + Uri phoneUri = Uri.withAppendedPath(mPersonRecord, + Contacts.People.Phones.CONTENT_DIRECTORY); + values.clear(); + values.put(Contacts.People.Phones.TYPE, Contacts.People.Phones.TYPE_HOME); + values.put(Contacts.People.Phones.NUMBER, TEST_PHONE_NUMBER); + mPhoneRecord = cr.insert(phoneUri, values); + + } catch (Exception e) { + assertTrue("Failed to insert test contact", false); + } } } @Override protected void tearDown() throws Exception { super.tearDown(); + ContentResolver resolver = getInstrumentation().getTargetContext().getContentResolver(); + + if (mPersonRecord != null) { + resolver.delete(mPersonRecord, null, null); + } + if(mPhoneRecord != null) { + resolver.delete(mPhoneRecord, null, null); + } + TestUtils.clearSystemDialerOverride(getInstrumentation()); TestUtils.removeTestEmergencyNumber(getInstrumentation(), TEST_EMERGENCY_NUMBER); } @@ -73,6 +114,20 @@ public class OutgoingCallTest extends BaseTelecomTestWithMockServices { } */ /** + * Verifies that providing content URI instead of tel/sip uri does not start a call + * + */ + public void testDoNotStartCallWithContentUri() { + if (!mShouldTestTelecom) { + return; + } + final Bundle extras = new Bundle(); + extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, mPhoneRecord); + placeAndVerifyNoCall(extras); + verifyNoConnectionForOutgoingCall(); + } + + /** * Verifies that providing the EXTRA_START_CALL_WITH_SPEAKERPHONE extra starts the call with * speakerphone automatically enabled. * diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java index 2560b942382..59d2394dd96 100644 --- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java +++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java @@ -138,6 +138,24 @@ public class TestUtils { .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) .build(); + public static final PhoneAccount TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME = + PhoneAccount.builder( + TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL) + .setAddress(Uri.parse("tel:555-TEST")) + .setSubscriptionAddress(Uri.parse("tel:555-TEST")) + .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | + PhoneAccount.CAPABILITY_VIDEO_CALLING | + PhoneAccount.CAPABILITY_RTT | + PhoneAccount.CAPABILITY_CONNECTION_MANAGER | + PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS | + PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING) + .setHighlightColor(Color.RED) + .setShortDescription(ACCOUNT_LABEL) + .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) + .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) + .addSupportedUriScheme("content") + .build(); + public static final PhoneAccount TEST_SIM_PHONE_ACCOUNT = PhoneAccount.builder( TEST_SIM_PHONE_ACCOUNT_HANDLE, SIM_ACCOUNT_LABEL) .setAddress(Uri.parse("tel:555-TEST")) diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java index 4b67468083e..c4a1e0c954d 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.os.OutcomeReceiver; import android.os.ParcelFileDescriptor; import android.os.ParcelUuid; +import android.telephony.ims.cts.ImsUtils; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -69,6 +70,9 @@ public class CallComposerTest { @Before public void setUp() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } mContext = InstrumentationRegistry.getContext(); overrideDefaultDialer(); mPreviousTestMode = Boolean.parseBoolean( @@ -80,6 +84,9 @@ public class CallComposerTest { @After public void tearDown() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } restoreDefaultDialer(); TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(), "cmd phone callcomposer test-mode " @@ -89,6 +96,9 @@ public class CallComposerTest { @Test public void testUploadPictureWithFile() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } Path testFile = mContext.getFilesDir().toPath().resolve(TEST_FILE_NAME); byte[] imageData = getSamplePictureAsBytes(); Files.write(testFile, imageData); @@ -99,6 +109,9 @@ public class CallComposerTest { @Test public void testUploadPictureAsStream() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } byte[] imageData = getSamplePictureAsBytes(); ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData); @@ -108,6 +121,9 @@ public class CallComposerTest { @Test public void testExcessivelyLargePictureAsFile() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } int targetSize = (int) TelephonyManager.getMaximumCallComposerPictureSize() + 1; byte[] imageData = getSamplePictureAsBytes(); byte[] paddedData = new byte[targetSize]; @@ -121,6 +137,9 @@ public class CallComposerTest { @Test public void testExcessivelyLargePictureAsStream() throws Exception { + if (!ImsUtils.shouldTestImsCall()) { + return; + } int targetSize = (int) TelephonyManager.getMaximumCallComposerPictureSize() + 1; byte[] imageData = getSamplePictureAsBytes(); byte[] paddedData = new byte[targetSize]; diff --git a/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java b/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java index d592e0f643c..0f52eb55fcc 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/DataProfileTest.java @@ -316,7 +316,8 @@ public class DataProfileTest { assertEquals(null, profile.getUserName()); assertEquals(null, profile.getPassword()); assertEquals(0, profile.getProfileId()); - assertEquals(ApnSetting.PROTOCOL_IP, profile.getProtocolType()); + assertTrue(profile.getProtocolType() == ApnSetting.PROTOCOL_IPV4V6 + || profile.getProtocolType() == ApnSetting.PROTOCOL_IP); assertEquals(ApnSetting.PROTOCOL_IP, profile.getRoamingProtocolType()); assertEquals(ApnSetting.TYPE_NONE, profile.getSupportedApnTypesBitmask()); assertEquals(DataProfile.TYPE_COMMON, profile.getType()); 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 03576df21c6..cf46203dbcb 100644 --- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java +++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java @@ -2271,7 +2271,7 @@ public class TelephonyManagerTest { List<String> plmns = mTelephonyManager.getEquivalentHomePlmns(); - if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) { + if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { assertEquals(0, plmns.size()); } else { for (String plmn : plmns) { diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java index 1c20e9af869..4f902a2ed76 100644 --- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java +++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallingTest.java @@ -208,7 +208,7 @@ public class ImsCallingTest { @BeforeClass public static void beforeAllTests() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -272,7 +272,7 @@ public class ImsCallingTest { @AfterClass public static void afterAllTests() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -308,7 +308,7 @@ public class ImsCallingTest { @Before public void beforeTest() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } TelephonyManager tm = (TelephonyManager) InstrumentationRegistry.getInstrumentation() @@ -365,7 +365,7 @@ public class ImsCallingTest { @After public void afterTest() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -389,7 +389,7 @@ public class ImsCallingTest { @Test public void testOutGoingCall() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -426,7 +426,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallStartFailed() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -474,7 +474,7 @@ public class ImsCallingTest { @Test public void testIncomingCall() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } bindImsService(); @@ -506,7 +506,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallForExecutor() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -545,7 +545,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallHoldResume() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -591,7 +591,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallHoldFailure() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -635,7 +635,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallResumeFailure() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -685,7 +685,7 @@ public class ImsCallingTest { @Test public void testOutGoingIncomingMultiCall() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -755,7 +755,7 @@ public class ImsCallingTest { @Test public void testOutGoingIncomingMultiCallAcceptTerminate() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -826,7 +826,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallSwap() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -877,7 +877,7 @@ public class ImsCallingTest { @Test public void testOutGoingCallSwapFail() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } @@ -929,7 +929,7 @@ public class ImsCallingTest { @Test public void testConferenceCall() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } Log.i(LOG_TAG, "testConference "); @@ -973,7 +973,7 @@ public class ImsCallingTest { @Test public void testConferenceCallFailure() throws Exception { - if (!ImsUtils.shouldTestImsService()) { + if (!ImsUtils.shouldTestImsCall()) { return; } Log.i(LOG_TAG, "testConferenceCallFailure "); diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java index b386e3caecd..adae12a946e 100644 --- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java +++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java @@ -67,6 +67,13 @@ public class ImsUtils { return hasTelephony && hasIms; } + public static boolean shouldTestImsCall() { + final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext() + .getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS) + && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING); + } + public static boolean shouldTestImsSingleRegistration() { final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext() .getPackageManager(); diff --git a/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java index bc03371036f..2e73d038d55 100644 --- a/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java +++ b/tests/tests/text/src/android/text/method/cts/BaseMovementMethodTest.java @@ -181,6 +181,7 @@ public class BaseMovementMethodTest { private TextView createTextView() { final TextView textView = new TextViewNoIme(mActivityRule.getActivity()); textView.setFocusable(true); + textView.setEllipsize(null); textView.setMovementMethod(mMovementMethod); textView.setTextDirection(View.TEXT_DIRECTION_LTR); return textView; diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java index 34ffd767a99..c967b05b355 100644 --- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java +++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java @@ -86,6 +86,7 @@ public class ScrollingMovementMethodTest { mTextView = new TextViewNoIme(mActivity); mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); mTextView.setText(THREE_LINES_TEXT, BufferType.EDITABLE); + mTextView.setEllipsize(null); mSpannable = (Spannable) mTextView.getText(); mScaledTouchSlop = ViewConfiguration.get(mActivity).getScaledTouchSlop(); } diff --git a/tests/tests/text/src/android/text/method/cts/TouchTest.java b/tests/tests/text/src/android/text/method/cts/TouchTest.java index fd078fb280d..127b87cb72b 100644 --- a/tests/tests/text/src/android/text/method/cts/TouchTest.java +++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java @@ -70,6 +70,7 @@ public class TouchTest { mActivity = mActivityRule.getActivity(); mTextView = new TextViewNoIme(mActivity); mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); + mTextView.setEllipsize(null); } @Test diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java index 84707ea0063..69d05864f5e 100644 --- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java +++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java @@ -1634,11 +1634,8 @@ public class TunerTest { mTuner.close(); mTuner = null; - // check the sharee is also closed - // tune() would have failed even before close() but still.. - // TODO: fix this once callback sharing is implemented - res = sharee.tune(feSettings); - assertEquals(Tuner.RESULT_UNAVAILABLE, res); + // check the frontend of sharee is also released + assertNull(sharee.getFrontendInfo()); sharee.close(); @@ -1660,7 +1657,6 @@ public class TunerTest { assertNotNull(statusCapabilities); FrontendStatus status = mTuner.getFrontendStatus(statusCapabilities); assertNotNull(status); - } @Test diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java index 823b02873bb..379f24bece8 100644 --- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java +++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java @@ -24,8 +24,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.Activity; +import android.app.ActivityOptions; import android.app.Instrumentation; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; @@ -41,10 +43,10 @@ import android.media.Image; import android.media.ImageReader; import android.media.ImageWriter; import android.os.Debug; -import android.server.wm.IgnoreOrientationRequestSession; import android.server.wm.SetRequestedOrientationRule; import android.util.Half; import android.util.Log; +import android.util.Pair; import android.view.PixelCopy; import android.view.Surface; import android.view.View; @@ -62,8 +64,10 @@ import com.android.compatibility.common.util.SynchronousPixelCopy; import org.junit.Assert; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExternalResource; import org.junit.rules.TestName; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -73,6 +77,7 @@ import org.junit.runners.model.Statement; import java.io.File; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -82,11 +87,9 @@ import java.util.function.Function; public class PixelCopyTest { private static final String TAG = "PixelCopyTests"; - // TODO: Use SetRequestedOrientationRule instead. - @Rule - public SetRequestedOrientationRule.DisableFixedToUserRotationRule - mDisableFixedToUserRotationRule = - new SetRequestedOrientationRule.DisableFixedToUserRotationRule(); + @ClassRule + public static SetRequestedOrientationRule mSetRequestedOrientationRule = + new SetRequestedOrientationRule(); @Rule public ActivityTestRule<PixelCopyGLProducerCtsActivity> mGLSurfaceViewActivityRule = @@ -96,18 +99,31 @@ public class PixelCopyTest { public ActivityTestRule<PixelCopyVideoSourceActivity> mVideoSourceActivityRule = new ActivityTestRule<>(PixelCopyVideoSourceActivity.class, false, false); - @Rule - public ActivityTestRule<PixelCopyViewProducerActivity> mWindowSourceActivityRule = - new ActivityTestRule<>(PixelCopyViewProducerActivity.class, false, false); + public static class FullscreenActivityRule extends ExternalResource { + private final ArrayList<Activity> mActivities = new ArrayList<>(); - @Rule - public ActivityTestRule<PixelCopyWideGamutViewProducerActivity> - mWideGamutWindowSourceActivityRule = new ActivityTestRule<>( - PixelCopyWideGamutViewProducerActivity.class, false, false); + public <T extends Activity> T launch(Class<T> klass) { + final Pair<Intent, ActivityOptions> args = + SetRequestedOrientationRule.buildFullScreenLaunchArgs(klass); + final T activity = (T) InstrumentationRegistry.getInstrumentation() + .startActivitySync(args.first, args.second.toBundle()); + mActivities.add(activity); + return activity; + } + + @Override + protected void after() { + if (mActivities.isEmpty()) return; + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + for (final Activity activity : mActivities) { + activity.finish(); + } + }); + } + } @Rule - public ActivityTestRule<PixelCopyViewProducerDialogActivity> mDialogSourceActivityRule = - new ActivityTestRule<>(PixelCopyViewProducerDialogActivity.class, false, false); + public FullscreenActivityRule mFullscreenActivityRule = new FullscreenActivityRule(); @Rule public SurfaceTextureRule mSurfaceRule = new SurfaceTextureRule(); @@ -125,24 +141,6 @@ public class PixelCopyTest { mCopyHelper = new SynchronousPixelCopy(); } - /** - * Helper method used to execute a runnable that enables the - * {@link Activity#setRequestedOrientation} API. - * - * On Android 12L large screen devices ignore requests to the setRequestedOrientation. - * So in order to support test cases that rely on this API, use - * {@link IgnoreOrientationRequestSession} to temporarily enable the setRequestedOrientation API - */ - private void withRequestedOrientationsEnabled(Runnable runnable) { - IgnoreOrientationRequestSession session = new IgnoreOrientationRequestSession( - false /* enable setRequestedOrientation */); - try { - runnable.run(); - } finally { - session.close(); - } - } - @Test(expected = IllegalArgumentException.class) public void testNullDest() { Bitmap dest = null; @@ -313,370 +311,327 @@ public class PixelCopyTest { assertNotEquals(generationId, bitmap.getGenerationId()); } - private Window waitForWindowProducerActivity() { - PixelCopyViewProducerActivity activity = - mWindowSourceActivityRule.launchActivity(null); + private PixelCopyViewProducerActivity waitForWindowProducerActivity() { + PixelCopyViewProducerActivity activity = mFullscreenActivityRule.launch( + PixelCopyViewProducerActivity.class); activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); - return activity.getWindow(); + return activity; } - private Rect makeWindowRect(int left, int top, int right, int bottom) { + private Rect makeWindowRect( + PixelCopyViewProducerActivity activity, int left, int top, int right, int bottom) { Rect r = new Rect(left, top, right, bottom); - mWindowSourceActivityRule.getActivity().normalizedToSurface(r); + activity.normalizedToSurface(r); return r; } @Test public void testWindowProducer() { - withRequestedOrientationsEnabled(() -> { - Bitmap bitmap; - Window window = waitForWindowProducerActivity(); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - do { - Rect src = makeWindowRect(0, 0, 100, 100); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); - int result = mCopyHelper.request(window, src, bitmap); - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.ARGB_8888, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - assertBitmapEdgeColor(bitmap, Color.YELLOW); - } while (activity.rotate()); - }); + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + do { + Rect src = makeWindowRect(activity, 0, 0, 100, 100); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.ARGB_8888, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + assertBitmapEdgeColor(bitmap, Color.YELLOW); + } while (activity.rotate()); } @Test public void testWindowProducerCropTopLeft() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWindowProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeWindowRect(0, 0, 50, 50), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.RED, Color.RED, Color.RED, Color.RED); - } while (activity.rotate()); - }); + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeWindowRect(activity, 0, 0, 50, 50), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.RED, Color.RED, Color.RED, Color.RED); + } while (activity.rotate()); } @Test public void testWindowProducerCropCenter() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWindowProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeWindowRect(25, 25, 75, 75), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeWindowRect(activity, 25, 25, 75, 75), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testWindowProducerCropBottomHalf() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWindowProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeWindowRect(0, 50, 100, 100), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeWindowRect(activity, 0, 50, 100, 100), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testWindowProducerScaling() { - withRequestedOrientationsEnabled(() -> { - // Since we only sample mid-pixel of each qudrant, filtering - // quality isn't tested - Window window = waitForWindowProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - // Make sure nothing messed with the bitmap - assertEquals(20, bitmap.getWidth()); - assertEquals(20, bitmap.getHeight()); - assertEquals(Config.ARGB_8888, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + // Since we only sample mid-pixel of each qudrant, filtering + // quality isn't tested + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); + do { + int result = mCopyHelper.request(activity.getWindow(), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + // Make sure nothing messed with the bitmap + assertEquals(20, bitmap.getWidth()); + assertEquals(20, bitmap.getHeight()); + assertEquals(Config.ARGB_8888, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testWindowProducerCopyToRGBA16F() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWindowProducerActivity(); - PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); - - Bitmap bitmap; - do { - Rect src = makeWindowRect(0, 0, 100, 100); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); - int result = mCopyHelper.request(window, src, bitmap); - // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's - // not support for float textures - if (result != PixelCopy.ERROR_DESTINATION_INVALID) { - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.RGBA_F16, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - assertBitmapEdgeColor(bitmap, Color.YELLOW); - } - } while (activity.rotate()); - }); + PixelCopyViewProducerActivity activity = waitForWindowProducerActivity(); + do { + Rect src = makeWindowRect(activity, 0, 0, 100, 100); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); + // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's + // not support for float textures + if (result != PixelCopy.ERROR_DESTINATION_INVALID) { + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.RGBA_F16, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + assertBitmapEdgeColor(bitmap, Color.YELLOW); + } + } while (activity.rotate()); } - private Window waitForWideGamutWindowProducerActivity() { - PixelCopyWideGamutViewProducerActivity activity = - mWideGamutWindowSourceActivityRule.launchActivity(null); + private PixelCopyWideGamutViewProducerActivity waitForWideGamutWindowProducerActivity() { + PixelCopyWideGamutViewProducerActivity activity = mFullscreenActivityRule.launch( + PixelCopyWideGamutViewProducerActivity.class); activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); - return activity.getWindow(); + return activity; } - private Rect makeWideGamutWindowRect(int left, int top, int right, int bottom) { + private Rect makeWideGamutWindowRect( + PixelCopyWideGamutViewProducerActivity activity, + int left, int top, int right, int bottom) { Rect r = new Rect(left, top, right, bottom); - mWideGamutWindowSourceActivityRule.getActivity().offsetForContent(r); + activity.offsetForContent(r); return r; } @Test public void testWideGamutWindowProducerCopyToRGBA8888() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWideGamutWindowProducerActivity(); - assertEquals( - ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, - window.getAttributes().getColorMode() - ); - - // Early out if the device does not support wide color gamut rendering - if (!window.isWideColorGamut()) { - return; - } + PixelCopyWideGamutViewProducerActivity activity = waitForWideGamutWindowProducerActivity(); + assertEquals( + ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, + activity.getWindow().getAttributes().getColorMode() + ); + + // Early out if the device does not support wide color gamut rendering + if (!activity.getWindow().isWideColorGamut()) { + return; + } - PixelCopyWideGamutViewProducerActivity activity = - mWideGamutWindowSourceActivityRule.getActivity(); + do { + Rect src = makeWideGamutWindowRect(activity, 0, 0, 128, 128); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); - Bitmap bitmap; - do { - Rect src = makeWideGamutWindowRect(0, 0, 128, 128); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); - int result = mCopyHelper.request(window, src, bitmap); - - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.ARGB_8888, bitmap.getConfig()); + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.ARGB_8888, bitmap.getConfig()); - assertEquals("Top left", Color.RED, bitmap.getPixel(32, 32)); - assertEquals("Top right", Color.GREEN, bitmap.getPixel(96, 32)); - assertEquals("Bottom left", Color.BLUE, bitmap.getPixel(32, 96)); - assertEquals("Bottom right", Color.YELLOW, bitmap.getPixel(96, 96)); - } while (activity.rotate()); - }); + assertEquals("Top left", Color.RED, bitmap.getPixel(32, 32)); + assertEquals("Top right", Color.GREEN, bitmap.getPixel(96, 32)); + assertEquals("Bottom left", Color.BLUE, bitmap.getPixel(32, 96)); + assertEquals("Bottom right", Color.YELLOW, bitmap.getPixel(96, 96)); + } while (activity.rotate()); } @Test public void testWideGamutWindowProducerCopyToRGBA16F() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForWideGamutWindowProducerActivity(); - assertEquals( - ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, - window.getAttributes().getColorMode() - ); - - // Early out if the device does not support wide color gamut rendering - if (!window.isWideColorGamut()) { - return; - } - - PixelCopyWideGamutViewProducerActivity activity = - mWideGamutWindowSourceActivityRule.getActivity(); - final WindowManager windowManager = (WindowManager) activity.getSystemService( - Context.WINDOW_SERVICE); - final ColorSpace colorSpace = windowManager.getDefaultDisplay() - .getPreferredWideGamutColorSpace(); - final ColorSpace.Connector proPhotoToDisplayWideColorSpace = ColorSpace.connect( - ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), colorSpace); - final ColorSpace.Connector displayWideColorSpaceToExtendedSrgb = ColorSpace.connect( - colorSpace, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); - - final float[] intermediateRed = - proPhotoToDisplayWideColorSpace.transform(1.0f, 0.0f, 0.0f); - final float[] intermediateGreen = proPhotoToDisplayWideColorSpace - .transform(0.0f, 1.0f, 0.0f); - final float[] intermediateBlue = proPhotoToDisplayWideColorSpace - .transform(0.0f, 0.0f, 1.0f); - final float[] intermediateYellow = proPhotoToDisplayWideColorSpace - .transform(1.0f, 1.0f, 0.0f); - - final float[] expectedRed = - displayWideColorSpaceToExtendedSrgb.transform(intermediateRed); - final float[] expectedGreen = displayWideColorSpaceToExtendedSrgb - .transform(intermediateGreen); - final float[] expectedBlue = displayWideColorSpaceToExtendedSrgb - .transform(intermediateBlue); - final float[] expectedYellow = displayWideColorSpaceToExtendedSrgb - .transform(intermediateYellow); - - Bitmap bitmap; - int i = 0; - do { - Rect src = makeWideGamutWindowRect(0, 0, 128, 128); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16, - true, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); - int result = mCopyHelper.request(window, src, bitmap); - - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.RGBA_F16, bitmap.getConfig()); + PixelCopyWideGamutViewProducerActivity activity = waitForWideGamutWindowProducerActivity(); + assertEquals( + ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, + activity.getWindow().getAttributes().getColorMode() + ); + + // Early out if the device does not support wide color gamut rendering + if (!activity.getWindow().isWideColorGamut()) { + return; + } - ByteBuffer dst = ByteBuffer.allocateDirect(bitmap.getAllocationByteCount()); - bitmap.copyPixelsToBuffer(dst); - dst.rewind(); - dst.order(ByteOrder.LITTLE_ENDIAN); - - // ProPhoto RGB red in scRGB-nl - assertEqualsRgba16f("Top left", bitmap, 32, 32, dst, expectedRed[0], - expectedRed[1], expectedRed[2], 1.0f); - // ProPhoto RGB green in scRGB-nl - assertEqualsRgba16f("Top right", bitmap, 96, 32, dst, - expectedGreen[0], expectedGreen[1], expectedGreen[2], 1.0f); - // ProPhoto RGB blue in scRGB-nl - assertEqualsRgba16f("Bottom left", bitmap, 32, 96, dst, - expectedBlue[0], expectedBlue[1], expectedBlue[2], 1.0f); - // ProPhoto RGB yellow in scRGB-nl - assertEqualsRgba16f("Bottom right", bitmap, 96, 96, dst, - expectedYellow[0], expectedYellow[1], expectedYellow[2], 1.0f); - } while (activity.rotate()); - }); + final WindowManager windowManager = (WindowManager) activity.getSystemService( + Context.WINDOW_SERVICE); + final ColorSpace colorSpace = windowManager.getDefaultDisplay() + .getPreferredWideGamutColorSpace(); + final ColorSpace.Connector proPhotoToDisplayWideColorSpace = ColorSpace.connect( + ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), colorSpace); + final ColorSpace.Connector displayWideColorSpaceToExtendedSrgb = ColorSpace.connect( + colorSpace, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); + + final float[] intermediateRed = + proPhotoToDisplayWideColorSpace.transform(1.0f, 0.0f, 0.0f); + final float[] intermediateGreen = proPhotoToDisplayWideColorSpace + .transform(0.0f, 1.0f, 0.0f); + final float[] intermediateBlue = proPhotoToDisplayWideColorSpace + .transform(0.0f, 0.0f, 1.0f); + final float[] intermediateYellow = proPhotoToDisplayWideColorSpace + .transform(1.0f, 1.0f, 0.0f); + + final float[] expectedRed = + displayWideColorSpaceToExtendedSrgb.transform(intermediateRed); + final float[] expectedGreen = displayWideColorSpaceToExtendedSrgb + .transform(intermediateGreen); + final float[] expectedBlue = displayWideColorSpaceToExtendedSrgb + .transform(intermediateBlue); + final float[] expectedYellow = displayWideColorSpaceToExtendedSrgb + .transform(intermediateYellow); + + do { + Rect src = makeWideGamutWindowRect(activity, 0, 0, 128, 128); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16, + true, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); + + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.RGBA_F16, bitmap.getConfig()); + + ByteBuffer dst = ByteBuffer.allocateDirect(bitmap.getAllocationByteCount()); + bitmap.copyPixelsToBuffer(dst); + dst.rewind(); + dst.order(ByteOrder.LITTLE_ENDIAN); + + // ProPhoto RGB red in scRGB-nl + assertEqualsRgba16f("Top left", bitmap, 32, 32, dst, expectedRed[0], + expectedRed[1], expectedRed[2], 1.0f); + // ProPhoto RGB green in scRGB-nl + assertEqualsRgba16f("Top right", bitmap, 96, 32, dst, + expectedGreen[0], expectedGreen[1], expectedGreen[2], 1.0f); + // ProPhoto RGB blue in scRGB-nl + assertEqualsRgba16f("Bottom left", bitmap, 32, 96, dst, + expectedBlue[0], expectedBlue[1], expectedBlue[2], 1.0f); + // ProPhoto RGB yellow in scRGB-nl + assertEqualsRgba16f("Bottom right", bitmap, 96, 96, dst, + expectedYellow[0], expectedYellow[1], expectedYellow[2], 1.0f); + } while (activity.rotate()); } - private Window waitForDialogProducerActivity() { - PixelCopyViewProducerActivity activity = - mDialogSourceActivityRule.launchActivity(null); + private PixelCopyViewProducerDialogActivity waitForDialogProducerActivity() { + PixelCopyViewProducerDialogActivity activity = mFullscreenActivityRule.launch( + PixelCopyViewProducerDialogActivity.class); activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); - return activity.getWindow(); + return activity; } - private Rect makeDialogRect(int left, int top, int right, int bottom) { + private Rect makeDialogRect( + PixelCopyViewProducerDialogActivity activity, + int left, int top, int right, int bottom) { Rect r = new Rect(left, top, right, bottom); - mDialogSourceActivityRule.getActivity().normalizedToSurface(r); + activity.normalizedToSurface(r); return r; } @Test public void testDialogProducer() { - withRequestedOrientationsEnabled(() -> { - Bitmap bitmap; - Window window = waitForDialogProducerActivity(); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - do { - Rect src = makeDialogRect(0, 0, 100, 100); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); - int result = mCopyHelper.request(window, src, bitmap); - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.ARGB_8888, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - assertBitmapEdgeColor(bitmap, Color.YELLOW); - } while (activity.rotate()); - }); + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + do { + Rect src = makeDialogRect(activity, 0, 0, 100, 100); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.ARGB_8888, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + assertBitmapEdgeColor(bitmap, Color.YELLOW); + } while (activity.rotate()); } @Test public void testDialogProducerCropTopLeft() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForDialogProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeDialogRect(0, 0, 50, 50), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.RED, Color.RED, Color.RED, Color.RED); - } while (activity.rotate()); - }); + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeDialogRect(activity, 0, 0, 50, 50), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.RED, Color.RED, Color.RED, Color.RED); + } while (activity.rotate()); } @Test public void testDialogProducerCropCenter() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForDialogProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeDialogRect(25, 25, 75, 75), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeDialogRect(activity, 25, 25, 75, 75), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testDialogProducerCropBottomHalf() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForDialogProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, makeDialogRect(0, 50, 100, 100), bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - assertBitmapQuadColor(bitmap, - Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); + do { + int result = mCopyHelper.request( + activity.getWindow(), makeDialogRect(activity, 0, 50, 100, 100), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + assertBitmapQuadColor(bitmap, + Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testDialogProducerScaling() { - withRequestedOrientationsEnabled(() -> { - // Since we only sample mid-pixel of each qudrant, filtering - // quality isn't tested - Window window = waitForDialogProducerActivity(); - Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - do { - int result = mCopyHelper.request(window, bitmap); - assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); - // Make sure nothing messed with the bitmap - assertEquals(20, bitmap.getWidth()); - assertEquals(20, bitmap.getHeight()); - assertEquals(Config.ARGB_8888, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - } while (activity.rotate()); - }); + // Since we only sample mid-pixel of each qudrant, filtering + // quality isn't tested + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); + do { + int result = mCopyHelper.request(activity.getWindow(), bitmap); + assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); + // Make sure nothing messed with the bitmap + assertEquals(20, bitmap.getWidth()); + assertEquals(20, bitmap.getHeight()); + assertEquals(Config.ARGB_8888, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + } while (activity.rotate()); } @Test public void testDialogProducerCopyToRGBA16F() { - withRequestedOrientationsEnabled(() -> { - Window window = waitForDialogProducerActivity(); - PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); - - Bitmap bitmap; - do { - Rect src = makeDialogRect(0, 0, 100, 100); - bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); - int result = mCopyHelper.request(window, src, bitmap); - // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's - // not support for float textures - if (result != PixelCopy.ERROR_DESTINATION_INVALID) { - assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); - assertEquals(Config.RGBA_F16, bitmap.getConfig()); - assertBitmapQuadColor(bitmap, - Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); - assertBitmapEdgeColor(bitmap, Color.YELLOW); - } - } while (activity.rotate()); - }); + PixelCopyViewProducerDialogActivity activity = waitForDialogProducerActivity(); + do { + Rect src = makeDialogRect(activity, 0, 0, 100, 100); + Bitmap bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); + int result = mCopyHelper.request(activity.getWindow(), src, bitmap); + // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's + // not support for float textures + if (result != PixelCopy.ERROR_DESTINATION_INVALID) { + assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); + assertEquals(Config.RGBA_F16, bitmap.getConfig()); + assertBitmapQuadColor(bitmap, + Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); + assertBitmapEdgeColor(bitmap, Color.YELLOW); + } + } while (activity.rotate()); } private static void assertEqualsRgba16f(String message, Bitmap bitmap, int x, int y, diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java index 83d794435a1..a72703fd269 100644 --- a/tests/tests/view/src/android/view/cts/TextureViewTest.java +++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java @@ -295,6 +295,7 @@ public class TextureViewTest { // paint surfaceView layer SurfaceView surfaceView = activity.getSurfaceView(); + final CountDownLatch latch = new CountDownLatch(1); surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { @@ -303,18 +304,32 @@ public class TextureViewTest { .setHardwareBufferFormat(PixelFormat.RGBA_8888) .setDataSpace(dataSpace) .build(); - Image image = writer.dequeueInputImage(); - assertEquals(dataSpace, image.getDataSpace()); - Image.Plane plane = image.getPlanes()[0]; - Bitmap bitmap = Bitmap.createBitmap(plane.getRowStride() / 4, image.getHeight(), - Bitmap.Config.ARGB_8888, true, ColorSpace.getFromDataSpace(dataSpace)); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setAntiAlias(false); - paint.setColor(converted); - canvas.drawRect(0f, 0f, width, height, paint); - bitmap.copyPixelsToBuffer(plane.getBuffer()); - writer.queueInputImage(image); + // spawn a thread here to iterate 10 times from image dequeue to queue + // so that we can be stalled until the first frame has been displayed. + new Thread(() -> { + Bitmap bitmap = null; + for (int i = 0; i < 10; i++) { + Image image = writer.dequeueInputImage(); + assertEquals(dataSpace, image.getDataSpace()); + Image.Plane plane = image.getPlanes()[0]; + // only make bitmap the first time to improve the performation + // if the bitmap is large. + if (bitmap == null) { + bitmap = Bitmap.createBitmap(plane.getRowStride() / 4, + image.getHeight(), + Bitmap.Config.ARGB_8888, true, + ColorSpace.getFromDataSpace(dataSpace)); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setAntiAlias(false); + paint.setColor(converted); + canvas.drawRect(0f, 0f, width, height, paint); + } + bitmap.copyPixelsToBuffer(plane.getBuffer()); + writer.queueInputImage(image); + } + latch.countDown(); + }).start(); } @Override @@ -329,9 +344,8 @@ public class TextureViewTest { activity.setContentView(surfaceView); }); - // wait here to ensure SF has latched the buffer that has been queued in - // this is the easiest way to solve copy failure but sacrifice the performance. - Thread.sleep(100); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + Bitmap surfaceViewScreenshot = mInstrumentation .getUiAutomation() .takeScreenshot(activity.getWindow()); @@ -374,7 +388,19 @@ public class TextureViewTest { WidgetTestUtils.runOnMainAndDrawSync( mSDRActivityRule, textureView, () -> textureView.getBitmap(textureViewScreenshot)); - assertTrue(textureViewScreenshot.sameAs(surfaceViewScreenshot)); + // sample 5 pixels on the edge for bitmap comparison. + // TextureView and SurfaceView use different shaders, so compare these two with tolerance. + final int threshold = 2; + assertTrue(pixelsAreSame(surfaceViewScreenshot.getPixel(width / 2, 0), + textureViewScreenshot.getPixel(width / 2, 0), threshold)); + assertTrue(pixelsAreSame(surfaceViewScreenshot.getPixel(0, height / 2), + textureViewScreenshot.getPixel(0, height / 2), threshold)); + assertTrue(pixelsAreSame(surfaceViewScreenshot.getPixel(width / 2, height / 2), + textureViewScreenshot.getPixel(width / 2, height / 2), threshold)); + assertTrue(pixelsAreSame(surfaceViewScreenshot.getPixel(width / 2, height - 1), + textureViewScreenshot.getPixel(width / 2, height - 1), threshold)); + assertTrue(pixelsAreSame(surfaceViewScreenshot.getPixel(width - 1, height / 2), + textureViewScreenshot.getPixel(width - 1, height / 2), threshold)); } @Test diff --git a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java index fa4833c1f06..8326962ab27 100644 --- a/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java +++ b/tests/tests/view/src/android/view/cts/View_UsingViewsTest.java @@ -392,15 +392,17 @@ public class View_UsingViewsTest { CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, mActivityRule, mEditText); verify(onLongClickListener, within(1000)).onLongClick(mEditText); + // Wait for the UI Thread to become idle. + final UiDevice device = UiDevice.getInstance(mInstrumentation); + // click the Cancel button mActivityRule.runOnUiThread(() -> mEditText.setText("Germany")); mInstrumentation.waitForIdleSync(); + device.waitForIdle(); CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mButtonCancel); assertEquals("", mEditText.getText().toString()); - // Wait for the UI Thread to become idle. - final UiDevice device = UiDevice.getInstance(mInstrumentation); mInstrumentation.waitForIdleSync(); device.waitForIdle(); diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java index c9ca1bd8ece..df2446c27d2 100644 --- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java +++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java @@ -48,6 +48,7 @@ import com.android.compatibility.common.util.SettingsStateChangerRule; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -191,6 +192,7 @@ public final class RecognitionServiceMicIndicatorTest { testVoiceRecognitionServiceBlameCallingApp(/* trustVoiceService */ false); } + @Ignore("b/266789512") @Test public void testTrustedRecognitionServiceCanBlameCallingApp() throws Throwable { // We treat trusted if the current voice recognizer is also a preinstalled app. This is a diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java index 767143ce802..5c1e926392f 100644 --- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java +++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java @@ -434,6 +434,8 @@ public final class HotwordDetectionServiceBasicTest // TODO ntmyren: test TV indicator } else if (sPkgMgr.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { // TODO ntmyren: test Auto indicator + } else if (sPkgMgr.hasSystemFeature(PackageManager.FEATURE_WATCH)) { + // The privacy chips/indicators are not implemented on Wear } else { verifyMicrophoneChipHandheld(shouldBePresent); } diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java index bc4018adfeb..0c63294eef9 100644 --- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import android.content.Context; import android.platform.test.annotations.AppModeFull; import android.webkit.CookieManager; import android.webkit.ValueCallback; @@ -32,7 +31,6 @@ import android.webkit.WebView; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.NullWebViewUtils; import com.android.compatibility.common.util.PollingCheck; @@ -54,12 +52,12 @@ import java.util.regex.Pattern; @AppModeFull @MediumTest @RunWith(AndroidJUnit4.class) -public class CookieManagerTest { +public class CookieManagerTest extends SharedWebViewTest { private static final int TEST_TIMEOUT = 5000; private CookieManager mCookieManager; private WebViewOnUiThread mOnUiThread; - private CtsTestServer mServer; + private SharedSdkWebServer mWebServer; @Rule public ActivityScenarioRule mActivityScenarioRule = @@ -67,15 +65,13 @@ public class CookieManagerTest { @Before public void setUp() throws Exception { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - mActivityScenarioRule.getScenario().onActivity(activity -> { - CookieSyncManagerCtsActivity cookieSyncManagerCtsActivity = - (CookieSyncManagerCtsActivity) activity; - WebView webView = cookieSyncManagerCtsActivity.getWebView(); - if (webView != null) { - mOnUiThread = new WebViewOnUiThread(webView); - } - }); + WebView webView = getTestEnvironment().getWebView(); + if (webView == null) { + return; + } + + mOnUiThread = new WebViewOnUiThread(webView); + mCookieManager = CookieManager.getInstance(); assertNotNull(mCookieManager); @@ -88,32 +84,37 @@ public class CookieManagerTest { assertFalse(mCookieManager.acceptCookie()); } + @Override + protected SharedWebViewTestEnvironment createTestEnvironment() { + Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); + + SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder(); + + mActivityScenarioRule + .getScenario() + .onActivity( + activity -> { + WebView webView = ((CookieSyncManagerCtsActivity) activity) + .getWebView(); + builder.setHostAppInvoker( + SharedWebViewTestEnvironment.createHostAppInvoker( + activity)) + .setWebView(webView); + }); + + return builder.build(); + } + @After public void tearDown() throws Exception { - if (mServer != null) { - mServer.shutdown(); + if (mWebServer != null) { + mWebServer.shutdown(); } if (mOnUiThread != null) { mOnUiThread.cleanUp(); } } - private CtsTestServer createWebServer() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - return new CtsTestServer(context); - } - - private CtsTestServer createWebServer(@SslMode int sslMode) throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - return new CtsTestServer(context, sslMode); - } - - private CtsTestServer createWebServer(@SslMode int sslMode, int keyResId, int certResId) - throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - return new CtsTestServer(context, sslMode, keyResId, certResId); - } - @Test public void testGetInstance() { mOnUiThread.cleanUp(); @@ -133,8 +134,8 @@ public class CookieManagerTest { mCookieManager.setAcceptCookie(false); assertFalse(mCookieManager.acceptCookie()); - mServer = createWebServer(SslMode.INSECURE); - String url = mServer.getCookieUrl("conquest.html"); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); + String url = mWebServer.getCookieUrl("conquest.html"); mOnUiThread.loadUrlAndWaitForCompletion(url); assertEquals("0", mOnUiThread.getTitle()); // no cookies passed Thread.sleep(500); @@ -143,7 +144,7 @@ public class CookieManagerTest { mCookieManager.setAcceptCookie(true); assertTrue(mCookieManager.acceptCookie()); - url = mServer.getCookieUrl("war.html"); + url = mWebServer.getCookieUrl("war.html"); mOnUiThread.loadUrlAndWaitForCompletion(url); assertEquals("0", mOnUiThread.getTitle()); // no cookies passed waitForCookie(url); @@ -155,7 +156,7 @@ public class CookieManagerTest { assertTrue(m.matches()); assertEquals("0", m.group(1)); - url = mServer.getCookieUrl("famine.html"); + url = mWebServer.getCookieUrl("famine.html"); mOnUiThread.loadUrlAndWaitForCompletion(url); assertEquals("1|count=0", mOnUiThread.getTitle()); // outgoing cookie waitForCookie(url); @@ -165,7 +166,7 @@ public class CookieManagerTest { assertTrue(m.matches()); assertEquals("1", m.group(1)); // value got incremented - url = mServer.getCookieUrl("death.html"); + url = mWebServer.getCookieUrl("death.html"); mCookieManager.setCookie(url, "count=41"); mOnUiThread.loadUrlAndWaitForCompletion(url); assertEquals("1|count=41", mOnUiThread.getTitle()); // outgoing cookie @@ -348,7 +349,7 @@ public class CookieManagerTest { // port. Instead we cheat making some of the urls come from localhost and some // from 127.0.0.1 which count (both in theory and pratice) as having different // origins. - mServer = createWebServer(); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); // Turn on Javascript (otherwise <script> aren't fetched spoiling the test). mOnUiThread.getSettings().setJavaScriptEnabled(true); @@ -364,9 +365,10 @@ public class CookieManagerTest { // ...we can't set third party cookies. // First on the third party server we get a url which tries to set a cookie. String cookieUrl = toThirdPartyUrl( - mServer.getSetCookieUrl("/cookie_1.js", "test1", "value1", "SameSite=None; Secure")); + mWebServer.getSetCookieUrl("/cookie_1.js", "test1", "value1", + "SameSite=None; Secure")); // Then we create a url on the first party server which links to the first url. - String url = mServer.getLinkedScriptUrl("/content_1.html", cookieUrl); + String url = mWebServer.getLinkedScriptUrl("/content_1.html", cookieUrl); mOnUiThread.loadUrlAndWaitForCompletion(url); assertNull(mCookieManager.getCookie(cookieUrl)); @@ -376,8 +378,8 @@ public class CookieManagerTest { // ...we can set third party cookies. cookieUrl = toThirdPartyUrl( - mServer.getSetCookieUrl("/cookie_2.js", "test2", "value2", "SameSite=None; Secure")); - url = mServer.getLinkedScriptUrl("/content_2.html", cookieUrl); + mWebServer.getSetCookieUrl("/cookie_2.js", "test2", "value2", "SameSite=None; Secure")); + url = mWebServer.getLinkedScriptUrl("/content_2.html", cookieUrl); mOnUiThread.loadUrlAndWaitForCompletion(url); waitForCookie(cookieUrl); String cookie = mCookieManager.getCookie(cookieUrl); @@ -387,7 +389,7 @@ public class CookieManagerTest { @Test public void testSameSiteLaxByDefault() throws Throwable { - mServer = createWebServer(); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.getSettings().setJavaScriptEnabled(true); mCookieManager.setAcceptCookie(true); mOnUiThread.setAcceptThirdPartyCookies(true); @@ -395,40 +397,42 @@ public class CookieManagerTest { // Verify that even with third party cookies enabled, cookies that don't explicitly // specify SameSite=none are treated as SameSite=lax and not set in a 3P context. String cookieUrl = toThirdPartyUrl( - mServer.getSetCookieUrl("/cookie_1.js", "test1", "value1")); - String url = mServer.getLinkedScriptUrl("/content_1.html", cookieUrl); + mWebServer.getSetCookieUrl("/cookie_1.js", "test1", "value1", null)); + String url = mWebServer.getLinkedScriptUrl("/content_1.html", cookieUrl); mOnUiThread.loadUrlAndWaitForCompletion(url); assertNull(mCookieManager.getCookie(cookieUrl)); } @Test public void testSameSiteNoneRequiresSecure() throws Throwable { - mServer = createWebServer(); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.getSettings().setJavaScriptEnabled(true); mCookieManager.setAcceptCookie(true); // Verify that cookies with SameSite=none are ignored when the cookie is not also Secure. String cookieUrl = - mServer.getSetCookieUrl("/cookie_1.js", "test1", "value1", "SameSite=None"); - String url = mServer.getLinkedScriptUrl("/content_1.html", cookieUrl); + mWebServer.getSetCookieUrl("/cookie_1.js", "test1", "value1", "SameSite=None"); + String url = mWebServer.getLinkedScriptUrl("/content_1.html", cookieUrl); mOnUiThread.loadUrlAndWaitForCompletion(url); assertNull(mCookieManager.getCookie(cookieUrl)); } @Test public void testSchemefulSameSite() throws Throwable { - mServer = createWebServer(); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.getSettings().setJavaScriptEnabled(true); mCookieManager.setAcceptCookie(true); mOnUiThread.setAcceptThirdPartyCookies(true); // Verify that two servers with different schemes on the same host are not considered // same-site to each other. - CtsTestServer secureServer = createWebServer(SslMode.NO_CLIENT_AUTH, R.raw.trustedkey, - R.raw.trustedcert); + SharedSdkWebServer secureServer = getTestEnvironment() + .getSetupWebServer(SslMode.NO_CLIENT_AUTH, null, + R.raw.trustedkey, R.raw.trustedcert); try { - String cookieUrl = secureServer.getSetCookieUrl("/cookie_1.js", "test1", "value1"); - String url = mServer.getLinkedScriptUrl("/content_1.html", cookieUrl); + String cookieUrl = secureServer.getSetCookieUrl("/cookie_1.js", "test1", + "value1", null); + String url = mWebServer.getLinkedScriptUrl("/content_1.html", cookieUrl); mOnUiThread.loadUrlAndWaitForCompletion(url); assertNull(mCookieManager.getCookie(cookieUrl)); } finally { diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java index ec7b24e8efe..6dcf019237f 100644 --- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java @@ -64,8 +64,7 @@ public class HttpAuthHandlerTest extends SharedWebViewTest { mOnUiThread = new WebViewOnUiThread(webview); } - mWebServer = getTestEnvironment().getWebServer(); - mWebServer.start(SslMode.INSECURE); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); } @After diff --git a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java index cc3b35631ac..e20a6b18353 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java @@ -95,8 +95,7 @@ public class WebBackForwardListTest extends SharedWebViewTest { assertNull(list.getItemAtIndex(-1)); assertNull(list.getItemAtIndex(2)); - SharedSdkWebServer server = getTestEnvironment().getWebServer(); - server.start(SslMode.INSECURE); + SharedSdkWebServer server = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); try { String url1 = server.getAssetUrl(TestHtmlConstants.HTML_URL1); String url2 = server.getAssetUrl(TestHtmlConstants.HTML_URL2); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java index 346a1815fae..c753bbd05c4 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java @@ -41,7 +41,6 @@ import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.NullWebViewUtils; import com.android.compatibility.common.util.PollingCheck; @@ -61,7 +60,7 @@ import java.util.concurrent.BlockingQueue; @AppModeFull @MediumTest @RunWith(AndroidJUnit4.class) -public class WebChromeClientTest { +public class WebChromeClientTest extends SharedWebViewTest{ private static final String JAVASCRIPT_UNLOAD = "javascript unload"; private static final String LISTENER_ADDED = "listener added"; private static final String TOUCH_RECEIVED = "touch received"; @@ -70,31 +69,21 @@ public class WebChromeClientTest { public ActivityScenarioRule mActivityScenarioRule = new ActivityScenarioRule(WebViewCtsActivity.class); - private CtsTestServer mWebServer; + private SharedSdkWebServer mWebServer; private WebIconDatabase mIconDb; private WebViewOnUiThread mOnUiThread; private boolean mBlockWindowCreationSync; private boolean mBlockWindowCreationAsync; - private WebViewCtsActivity mActivity; @Before public void setUp() throws Exception { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - mActivityScenarioRule.getScenario().onActivity(activity -> { - mActivity = (WebViewCtsActivity) activity; - WebView webview = mActivity.getWebView(); - if (webview != null) { - mOnUiThread = new WebViewOnUiThread(webview); - } - try { - mWebServer = new CtsTestServer(mActivity); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); + WebView webview = getTestEnvironment().getWebView(); + if (webview != null) { + mOnUiThread = new WebViewOnUiThread(webview); + } + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); } - @After public void tearDown() throws Exception { if (mOnUiThread != null) { @@ -109,6 +98,30 @@ public class WebChromeClientTest { } } + @Override + protected SharedWebViewTestEnvironment createTestEnvironment() { + Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); + + SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder(); + + mActivityScenarioRule + .getScenario() + .onActivity( + activity -> { + WebView webView = ((WebViewCtsActivity) activity).getWebView(); + builder.setHostAppInvoker( + SharedWebViewTestEnvironment.createHostAppInvoker( + activity)) + .setContext(activity) + .setWebView(webView) + .setRootLayout(((WebViewCtsActivity) activity).getRootLayout()); + }); + + SharedWebViewTestEnvironment environment = builder.build(); + return environment; + } + + @Test public void testOnProgressChanged() { final MockWebChromeClient webChromeClient = new MockWebChromeClient(); @@ -153,10 +166,10 @@ public class WebChromeClientTest { WebkitUtils.onMainThreadSync(() -> { // getInstance must run on the UI thread mIconDb = WebIconDatabase.getInstance(); - String dbPath = mActivity.getFilesDir().toString() + "/icons"; + String dbPath = getTestEnvironment().getContext().getFilesDir().toString() + "/icons"; mIconDb.open(dbPath); }); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + getTestEnvironment().waitForIdleSync(); Thread.sleep(100); // Wait for open to be received on the icon db thread. assertFalse(webChromeClient.hadOnReceivedIcon()); @@ -412,17 +425,17 @@ public class WebChromeClientTest { int middleY = location[1] + mOnUiThread.getWebView().getHeight() / 2; long timeDown = SystemClock.uptimeMillis(); - InstrumentationRegistry.getInstrumentation().sendPointerSync( + getTestEnvironment().sendPointerSync( MotionEvent.obtain(timeDown, timeDown, MotionEvent.ACTION_DOWN, middleX, middleY, 0)); long timeUp = SystemClock.uptimeMillis(); - InstrumentationRegistry.getInstrumentation().sendPointerSync( + getTestEnvironment().sendPointerSync( MotionEvent.obtain(timeUp, timeUp, MotionEvent.ACTION_UP, middleX, middleY, 0)); // Wait for the system to process all events in the queue - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + getTestEnvironment().waitForIdleSync(); } private class MockWebChromeClient extends WaitForProgressClient { @@ -573,12 +586,12 @@ public class WebChromeClientTest { if (mBlockWindowCreationAsync) { transport.setWebView(null); } else { - mChildWebView = new WebView(mActivity); + mChildWebView = new WebView(getTestEnvironment().getContext()); final WebSettings settings = mChildWebView.getSettings(); settings.setJavaScriptEnabled(true); mChildWebView.setWebChromeClient(this); transport.setWebView(mChildWebView); - mActivity.addContentView(mChildWebView, new ViewGroup.LayoutParams( + getTestEnvironment().addContentView(mChildWebView, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } resultMsg.sendToTarget(); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java index df48ce1f41b..d0881d9bbac 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java @@ -78,8 +78,7 @@ public class WebHistoryItemTest extends SharedWebViewTest { mOnUiThread = new WebViewOnUiThread(webview); } mContext = getTestEnvironment().getContext(); - mWebServer = getTestEnvironment().getWebServer(); - mWebServer.start(SslMode.INSECURE); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); } @After diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java index 81c1eeee272..d44cbb03b24 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.content.Context; @@ -48,7 +47,6 @@ import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.NullWebViewUtils; import com.android.compatibility.common.util.PollingCheck; @@ -76,7 +74,7 @@ import java.util.regex.Pattern; @AppModeFull @MediumTest @RunWith(AndroidJUnit4.class) -public class WebSettingsTest { +public class WebSettingsTest extends SharedWebViewTest { private static final String LOG_TAG = "WebSettingsTest"; private final String EMPTY_IMAGE_HEIGHT = "0"; @@ -96,23 +94,18 @@ public class WebSettingsTest { new ActivityScenarioRule(WebViewCtsActivity.class); private WebSettings mSettings; - private CtsTestServer mWebServer; + private SharedSdkWebServer mWebServer; private WebViewOnUiThread mOnUiThread; private Context mContext; @Before public void setUp() throws Exception { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - - mActivityScenarioRule.getScenario().onActivity(activity -> { - WebViewCtsActivity webviewCtsActivity = (WebViewCtsActivity) activity; - WebView webview = webviewCtsActivity.getWebView(); - if (webview != null) { - mOnUiThread = new WebViewOnUiThread(webview); - } - }); + WebView webview = getTestEnvironment().getWebView(); + if (webview != null) { + mOnUiThread = new WebViewOnUiThread(webview); + } mSettings = mOnUiThread.getSettings(); - mContext = InstrumentationRegistry.getInstrumentation().getContext(); + mContext = getTestEnvironment().getContext(); } @@ -126,6 +119,28 @@ public class WebSettingsTest { } } + @Override + protected SharedWebViewTestEnvironment createTestEnvironment() { + Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); + + SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder(); + + mActivityScenarioRule + .getScenario() + .onActivity( + activity -> { + WebView webView = ((WebViewCtsActivity) activity).getWebView(); + builder.setHostAppInvoker( + SharedWebViewTestEnvironment.createHostAppInvoker( + activity)) + .setContext(activity) + .setWebView(webView) + .setRootLayout(((WebViewCtsActivity) activity).getRootLayout()); + }); + + return builder.build(); + } + /** * Verifies that the default user agent string follows the format defined in Android * compatibility definition (tokens in angle brackets are variables, tokens in square @@ -219,7 +234,7 @@ public class WebSettingsTest { @Test public void testAccessUserAgentString() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getUserAgentUrl(); String defaultUserAgent = mSettings.getUserAgentString(); @@ -292,7 +307,7 @@ public class WebSettingsTest { String dbPath = mContext.getFilesDir().toString() + "/icons"; iconDb.open(dbPath); }); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + getTestEnvironment().waitForIdleSync(); Thread.sleep(100); // Wait for open to be received on the icon db thread. } @@ -301,7 +316,7 @@ public class WebSettingsTest { openIconDatabase(); final IconListenerClient iconListener = new IconListenerClient(); mOnUiThread.setWebChromeClient(iconListener); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); assertEquals(WebSettings.LOAD_CACHE_ELSE_NETWORK, mSettings.getCacheMode()); @@ -324,7 +339,7 @@ public class WebSettingsTest { openIconDatabase(); final IconListenerClient iconListener = new IconListenerClient(); mOnUiThread.setWebChromeClient(iconListener); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); assertEquals(WebSettings.LOAD_NO_CACHE, mSettings.getCacheMode()); @@ -347,7 +362,7 @@ public class WebSettingsTest { openIconDatabase(); final IconListenerClient iconListener = new IconListenerClient(); mOnUiThread.setWebChromeClient(iconListener); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); // As a precondition, get the icon in the cache. mSettings.setCacheMode(WebSettings.LOAD_DEFAULT); @@ -474,7 +489,7 @@ public class WebSettingsTest { public void testAccessJavaScriptCanOpenWindowsAutomatically() throws Exception { mSettings.setJavaScriptEnabled(true); mSettings.setSupportMultipleWindows(true); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final WebView childWebView = mOnUiThread.createWebView(); final SettableFuture<Void> createWindowFuture = SettableFuture.create(); @@ -678,7 +693,7 @@ public class WebSettingsTest { public void testAppCacheDisabled() throws Throwable { // Test that when AppCache is disabled, we don't get any AppCache // callbacks. - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getAppCacheUrl(); mSettings.setJavaScriptEnabled(true); @@ -702,7 +717,7 @@ public class WebSettingsTest { // Test that when AppCache is enabled but no valid path is provided, // we don't get any AppCache callbacks. - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getAppCacheUrl(); mSettings.setAppCacheEnabled(true); mSettings.setJavaScriptEnabled(true); @@ -736,7 +751,7 @@ public class WebSettingsTest { @Test public void testDatabaseDisabled() throws Throwable { // Verify that websql database does not work when disabled. - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.setWebChromeClient(new WebViewSyncLoader.WaitForProgressClient(mOnUiThread) { @Override @@ -776,7 +791,7 @@ public class WebSettingsTest { @Test public void testLoadsImagesAutomatically_httpImagesLoaded() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); mSettings.setLoadsImagesAutomatically(true); @@ -786,7 +801,7 @@ public class WebSettingsTest { @Test public void testLoadsImagesAutomatically_dataUriImagesLoaded() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); mSettings.setLoadsImagesAutomatically(true); @@ -796,7 +811,7 @@ public class WebSettingsTest { @Test public void testLoadsImagesAutomatically_blockLoadingImages() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); mSettings.setLoadsImagesAutomatically(false); @@ -810,7 +825,7 @@ public class WebSettingsTest { @Test public void testLoadsImagesAutomatically_loadImagesWithoutReload() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); mSettings.setLoadsImagesAutomatically(false); @@ -834,7 +849,7 @@ public class WebSettingsTest { public void testBlockNetworkImage() throws Throwable { assertFalse(mSettings.getBlockNetworkImage()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); // Check that by default network and data url images are loaded. @@ -864,7 +879,7 @@ public class WebSettingsTest { public void testBlockNetworkLoads() throws Throwable { assertFalse(mSettings.getBlockNetworkLoads()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mSettings.setJavaScriptEnabled(true); // Check that by default network resources and data url images are loaded. @@ -1047,7 +1062,7 @@ public class WebSettingsTest { mOnUiThread.setWebViewClient(interceptClient); mSettings.setJavaScriptEnabled(true); - startWebServer(true); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); String secureUrl = mWebServer.setResponse(SECURE_URL, SECURE_HTML, null); mOnUiThread.clearSslPreferences(); @@ -1098,17 +1113,6 @@ public class WebSettingsTest { } /** - * Starts the internal web server. The server will be shut down automatically - * during tearDown(). - * - * @throws Exception - */ - private void startWebServer(boolean secure) throws Exception { - assertNull(mWebServer); - mWebServer = new CtsTestServer(mContext, secure ? SslMode.NO_CLIENT_AUTH : SslMode.INSECURE); - } - - /** * Load the given asset from the internal web server. Starts the server if * it is not already running. * @@ -1117,7 +1121,7 @@ public class WebSettingsTest { */ private void loadAssetUrl(String asset) throws Exception { if (mWebServer == null) { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); } String url = mWebServer.getAssetUrl(asset); mOnUiThread.loadUrlAndWaitForCompletion(url); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java index 03375fe2796..cbe038c955a 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java @@ -25,9 +25,9 @@ import static org.junit.Assert.assertTrue; import android.graphics.Bitmap; import android.os.Message; import android.platform.test.annotations.AppModeFull; -import android.util.Pair; import android.view.KeyEvent; import android.view.ViewGroup; +import android.view.ViewParent; import android.webkit.HttpAuthHandler; import android.webkit.RenderProcessGoneDetail; import android.webkit.SafeBrowsingResponse; @@ -43,7 +43,6 @@ import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.MediumTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.NullWebViewUtils; import com.android.compatibility.common.util.PollingCheck; @@ -67,7 +66,7 @@ import java.util.Map; @AppModeFull @MediumTest @RunWith(AndroidJUnit4.class) -public class WebViewClientTest { +public class WebViewClientTest extends SharedWebViewTest { private static final String TEST_URL = "http://www.example.com/"; @Rule @@ -75,8 +74,7 @@ public class WebViewClientTest { new ActivityScenarioRule(WebViewCtsActivity.class); private WebViewOnUiThread mOnUiThread; - private CtsTestServer mWebServer; - private WebViewCtsActivity mActivity; + private SharedSdkWebServer mWebServer; private static final String TEST_SAFE_BROWSING_URL_PREFIX = "chrome://safe-browsing/match?type="; @@ -91,20 +89,10 @@ public class WebViewClientTest { @Before public void setUp() throws Exception { - Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - mActivityScenarioRule.getScenario().onActivity(activity -> { - mActivity = (WebViewCtsActivity) activity; - WebView webview = mActivity.getWebView(); - if (webview != null) { - new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { - @Override - protected boolean check() { - return activity.hasWindowFocus(); - } - }.run(); - mOnUiThread = new WebViewOnUiThread(webview); - } - }); + WebView webview = getTestEnvironment().getWebView(); + if (webview != null) { + mOnUiThread = new WebViewOnUiThread(webview); + } } @After @@ -117,6 +105,40 @@ public class WebViewClientTest { } } + @Override + protected SharedWebViewTestEnvironment createTestEnvironment() { + Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); + + SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder(); + + mActivityScenarioRule + .getScenario() + .onActivity( + activity -> { + WebView webView = ((WebViewCtsActivity) activity).getWebView(); + + builder.setHostAppInvoker( + SharedWebViewTestEnvironment.createHostAppInvoker( + activity)) + .setContext(activity) + .setWebView(webView) + .setRootLayout(((WebViewCtsActivity) activity).getRootLayout()); + }); + + SharedWebViewTestEnvironment environment = builder.build(); + + if (environment.getWebView() != null) { + new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { + @Override + protected boolean check() { + return ((WebViewCtsActivity) environment.getContext()).hasWindowFocus(); + } + }.run(); + } + + return environment; + } + /** * This should remain functionally equivalent to * androidx.webkit.WebViewClientCompatTest#testShouldOverrideUrlLoadingDefault. Modifications @@ -157,7 +179,7 @@ public class WebViewClientTest { // TODO(sgurun) upstream this test to Aw. @Test public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception { - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); // WebViewClient for main window final MockWebViewClient mainWebViewClient = new MockWebViewClient(); // WebViewClient for child window @@ -169,56 +191,70 @@ public class WebViewClientTest { final WebView childWebView = mOnUiThread.createWebView(); - WebViewOnUiThread childWebViewOnUiThread = new WebViewOnUiThread(childWebView); - mOnUiThread.setWebChromeClient(new WebChromeClient() { - @Override - public boolean onCreateWindow( - WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { - WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; - childWebView.setWebViewClient(childWebViewClient); - childWebView.getSettings().setJavaScriptEnabled(true); - transport.setWebView(childWebView); - mActivity.addContentView(childWebView, new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - resultMsg.sendToTarget(); - return true; - } - }); - { - final int childCallCount = childWebViewClient.getShouldOverrideUrlLoadingCallCount(); - mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_TAG_URL)); - - new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { - @Override - protected boolean check() { - return childWebViewClient.hasOnPageFinishedCalled(); - } - }.run(); - new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { - @Override - protected boolean check() { - return childWebViewClient.getShouldOverrideUrlLoadingCallCount() > childCallCount; - } - }.run(); - assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.PAGE_WITH_LINK_URL), - childWebViewClient.getLastShouldOverrideUrl()); - } - - final int childCallCount = childWebViewClient.getShouldOverrideUrlLoadingCallCount(); - final int mainCallCount = mainWebViewClient.getShouldOverrideUrlLoadingCallCount(); - clickOnLinkUsingJs("link", childWebViewOnUiThread); - new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { - @Override - protected boolean check() { - return childWebViewClient.getShouldOverrideUrlLoadingCallCount() > childCallCount; + try { + WebViewOnUiThread childWebViewOnUiThread = new WebViewOnUiThread(childWebView); + mOnUiThread.setWebChromeClient(new WebChromeClient() { + @Override + public boolean onCreateWindow( + WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { + WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + childWebView.setWebViewClient(childWebViewClient); + childWebView.getSettings().setJavaScriptEnabled(true); + transport.setWebView(childWebView); + getTestEnvironment().addContentView(childWebView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + resultMsg.sendToTarget(); + return true; + } + }); + { + final int childCallCount = childWebViewClient + .getShouldOverrideUrlLoadingCallCount(); + mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_TAG_URL)); + + new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { + @Override + protected boolean check() { + return childWebViewClient.hasOnPageFinishedCalled(); + } + }.run(); + new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { + @Override + protected boolean check() { + return childWebViewClient + .getShouldOverrideUrlLoadingCallCount() > childCallCount; + } + }.run(); + assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.PAGE_WITH_LINK_URL), + childWebViewClient.getLastShouldOverrideUrl()); } - }.run(); - assertEquals(mainCallCount, mainWebViewClient.getShouldOverrideUrlLoadingCallCount()); - // PAGE_WITH_LINK_URL has a link to BLANK_PAGE_URL (an arbitrary page also controlled by the - // test server) - assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL), - childWebViewClient.getLastShouldOverrideUrl()); + + final int childCallCount = childWebViewClient.getShouldOverrideUrlLoadingCallCount(); + final int mainCallCount = mainWebViewClient.getShouldOverrideUrlLoadingCallCount(); + clickOnLinkUsingJs("link", childWebViewOnUiThread); + new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { + @Override + protected boolean check() { + return childWebViewClient + .getShouldOverrideUrlLoadingCallCount() > childCallCount; + } + }.run(); + assertEquals(mainCallCount, mainWebViewClient.getShouldOverrideUrlLoadingCallCount()); + // PAGE_WITH_LINK_URL has a link to BLANK_PAGE_URL (an arbitrary page + // also controlled by the test server) + assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL), + childWebViewClient.getLastShouldOverrideUrl()); + + } finally { + WebkitUtils.onMainThreadSync(() -> { + ViewParent parent = childWebView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(childWebView); + } + childWebView.destroy(); + }); + } } private void clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread) { @@ -231,7 +267,7 @@ public class WebViewClientTest { public void testLoadPage() throws Exception { final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); assertFalse(webViewClient.hasOnPageStartedCalled()); @@ -271,10 +307,10 @@ public class WebViewClientTest { final String page = "<head></head><body>test onReceivedLoginRequest</body>"; final String headerName = "x-auto-login"; final String headerValue = "realm=com.google&account=foo%40bar.com&args=random_string"; - List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); - headers.add(Pair.create(headerName, headerValue)); + List<HttpHeader> headers = new ArrayList<HttpHeader>(); + headers.add(HttpHeader.create(headerName, headerValue)); - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.setResponse(path, page, headers); assertFalse(webViewClient.hasOnReceivedLoginRequest()); mOnUiThread.loadUrlAndWaitForCompletion(url); @@ -313,9 +349,10 @@ public class WebViewClientTest { */ @Test public void testOnReceivedErrorForSubresource() throws Exception { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); + final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); assertNull(webViewClient.hasOnReceivedResourceError()); String url = mWebServer.getAssetUrl(TestHtmlConstants.BAD_IMAGE_PAGE_URL); @@ -327,9 +364,9 @@ public class WebViewClientTest { @Test public void testOnReceivedHttpError() throws Exception { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); assertNull(webViewClient.hasOnReceivedHttpError()); String url = mWebServer.getAssetUrl(TestHtmlConstants.NON_EXISTENT_PAGE_URL); @@ -340,11 +377,11 @@ public class WebViewClientTest { @Test public void testOnFormResubmission() throws Exception { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); final WebSettings settings = mOnUiThread.getSettings(); settings.setJavaScriptEnabled(true); - mWebServer = new CtsTestServer(mActivity); assertFalse(webViewClient.hasOnFormResubmissionCalled()); String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_FORM_URL); @@ -366,9 +403,9 @@ public class WebViewClientTest { @Test public void testDoUpdateVisitedHistory() throws Exception { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); assertFalse(webViewClient.hasDoUpdateVisitedHistoryCalled()); String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); @@ -385,9 +422,9 @@ public class WebViewClientTest { @Test public void testOnReceivedHttpAuthRequest() throws Exception { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); assertFalse(webViewClient.hasOnReceivedHttpAuthRequestCalled()); String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.EMBEDDED_IMG_URL); @@ -410,10 +447,10 @@ public class WebViewClientTest { mOnUiThread.setWebViewClient(webViewClient); mOnUiThread.requestFocus(); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + getTestEnvironment().waitForIdleSync(); assertFalse(webViewClient.hasOnUnhandledKeyEventCalled()); - InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_1); + getTestEnvironment().sendKeyDownUpSync(KeyEvent.KEYCODE_1); new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) { @Override @@ -425,9 +462,9 @@ public class WebViewClientTest { @Test public void testOnScaleChanged() throws Throwable { + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); - mWebServer = new CtsTestServer(mActivity); assertFalse(webViewClient.hasOnScaleChangedCalled()); String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); @@ -488,14 +525,14 @@ public class WebViewClientTest { TestClient client = new TestClient(); mOnUiThread.setWebViewClient(client); - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String mainUrl = mWebServer.setResponse(mainPath, mainPage, null); mOnUiThread.loadUrlAndWaitForCompletion(mainUrl, headers); // Inspect the fields of the saved WebResourceRequest assertNotNull(client.interceptRequest); assertEquals(mainUrl, client.interceptRequest.getUrl().toString()); assertTrue(client.interceptRequest.isForMainFrame()); - assertEquals(mWebServer.getLastRequest(mainPath).getRequestLine().getMethod(), + assertEquals(mWebServer.getLastRequest(mainPath).getMethod(), client.interceptRequest.getMethod()); // Web request headers are case-insensitive. We provided lower-case headerName and // headerValue. This will pass implementations which either do not mangle case, @@ -537,7 +574,7 @@ public class WebViewClientTest { TestClient client = new TestClient(); mOnUiThread.setWebViewClient(client); - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String interceptUrl = mWebServer.getAbsoluteUrl(interceptPath); // JavaScript which makes a synchronous AJAX request and logs and returns the status String js = @@ -594,7 +631,7 @@ public class WebViewClientTest { */ @Test public void testOnSafeBrowsingHitBackToSafety() throws Throwable { - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); final String ORIGINAL_URL = mOnUiThread.getUrl(); @@ -629,7 +666,7 @@ public class WebViewClientTest { */ @Test public void testOnSafeBrowsingHitProceed() throws Throwable { - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); final String ORIGINAL_URL = mOnUiThread.getUrl(); @@ -653,7 +690,7 @@ public class WebViewClientTest { private void testOnSafeBrowsingCode(String expectedUrl, int expectedThreatType) throws Throwable { - mWebServer = new CtsTestServer(mActivity); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); final String ORIGINAL_URL = mOnUiThread.getUrl(); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java index b9136067ecc..e47568d7100 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java @@ -463,7 +463,7 @@ public class WebViewSslTest extends SharedWebViewTest { mOnUiThread.cleanUp(); } if (mWebServer != null) { - stopWebServer(); + stopWebServer(mWebServer); } mActivity = null; } @@ -505,25 +505,15 @@ public class WebViewSslTest extends SharedWebViewTest { return environment; } - private void startWebServer(@SslMode int sslMode) throws Exception { - startWebServer(new SharedSdkWebServer.Config().setSslMode(sslMode)); - } - - private void startWebServer(SharedSdkWebServer.Config config) throws Exception { - assertNull(mWebServer); - mWebServer = getTestEnvironment().getWebServer(); - mWebServer.start(config); - } - - private void stopWebServer() throws Exception { - assertNotNull(mWebServer); + private void stopWebServer(SharedSdkWebServer webServer) throws Exception { + assertNotNull(webServer); ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); ThreadPolicy tmpPolicy = new ThreadPolicy.Builder(oldPolicy) .permitNetwork() .build(); StrictMode.setThreadPolicy(tmpPolicy); - mWebServer.shutdown(); - mWebServer = null; + webServer.shutdown(); + webServer = null; StrictMode.setThreadPolicy(oldPolicy); } @@ -539,7 +529,7 @@ public class WebViewSslTest extends SharedWebViewTest { } } - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); mOnUiThread.setWebViewClient(new MockWebViewClient()); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL)); @@ -547,9 +537,9 @@ public class WebViewSslTest extends SharedWebViewTest { assertNotNull(cert); assertEquals("Android", cert.getIssuedTo().getUName()); - stopWebServer(); + stopWebServer(mWebServer); - startWebServer(SslMode.INSECURE); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL)); assertNull(mOnUiThread.getCertificate()); @@ -557,6 +547,8 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testSecureSiteSetsCertificate() throws Throwable { + SharedWebViewTestEnvironment testEnvironment = getTestEnvironment(); + final class MockWebViewClient extends WaitForLoadedClient { public MockWebViewClient() { super(mOnUiThread); @@ -567,14 +559,14 @@ public class WebViewSslTest extends SharedWebViewTest { } } - startWebServer(SslMode.INSECURE); + mWebServer = testEnvironment.getSetupWebServer(SslMode.INSECURE); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL)); assertNull(mOnUiThread.getCertificate()); - stopWebServer(); + stopWebServer(mWebServer); - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = testEnvironment.getSetupWebServer(SslMode.NO_CLIENT_AUTH); mOnUiThread.setWebViewClient(new MockWebViewClient()); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL)); @@ -588,7 +580,7 @@ public class WebViewSslTest extends SharedWebViewTest { // Load the first page. We expect a call to // WebViewClient.onReceivedSslError(). final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient(mOnUiThread); - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.setWebViewClient(webViewClient); mOnUiThread.clearSslPreferences(); @@ -637,7 +629,7 @@ public class WebViewSslTest extends SharedWebViewTest { } } - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String errorUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final MockWebViewClient webViewClient = new MockWebViewClient(); mOnUiThread.setWebViewClient(webViewClient); @@ -660,7 +652,7 @@ public class WebViewSslTest extends SharedWebViewTest { } } - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.setWebViewClient(new MockWebViewClient()); mOnUiThread.loadUrlAndWaitForCompletion(url); @@ -679,7 +671,7 @@ public class WebViewSslTest extends SharedWebViewTest { } } - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.setWebViewClient(new MockWebViewClient()); mOnUiThread.clearSslPreferences(); @@ -692,7 +684,7 @@ public class WebViewSslTest extends SharedWebViewTest { // Load the first page. We expect a call to // WebViewClient.onReceivedSslError(). final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient(mOnUiThread); - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String firstUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1); mOnUiThread.setWebViewClient(webViewClient); mOnUiThread.clearSslPreferences(); @@ -715,7 +707,7 @@ public class WebViewSslTest extends SharedWebViewTest { // Load the first page. We expect a call to // WebViewClient.onReceivedSslError(). final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient(mOnUiThread); - startWebServer(SslMode.NO_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NO_CLIENT_AUTH); final String firstUrl = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1); mOnUiThread.setWebViewClient(webViewClient); mOnUiThread.clearSslPreferences(); @@ -738,7 +730,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testSecureServerRequestingClientCertDoesNotCancelRequest() throws Throwable { - startWebServer(SslMode.WANTS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.WANTS_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); @@ -753,7 +745,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testSecureServerRequiringClientCertDoesCancelRequest() throws Throwable { - startWebServer(SslMode.NEEDS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); @@ -779,7 +771,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testProceedClientCertRequest() throws Throwable { - startWebServer(SslMode.NEEDS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final ClientCertWebViewClient webViewClient = new ClientCertWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); @@ -807,7 +799,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testProceedClientCertRequestKeyWithAndroidKeystoreKey() throws Throwable { - startWebServer(SslMode.NEEDS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final ClientCertWebViewClient webViewClient = new ClientCertWebViewClient( mOnUiThread, @@ -858,7 +850,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testIgnoreClientCertRequest() throws Throwable { - startWebServer(SslMode.NEEDS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final ClientCertWebViewClient webViewClient = new ClientCertWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); @@ -892,7 +884,7 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testCancelClientCertRequest() throws Throwable { - startWebServer(SslMode.NEEDS_CLIENT_AUTH); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final ClientCertWebViewClient webViewClient = new ClientCertWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); @@ -917,10 +909,8 @@ public class WebViewSslTest extends SharedWebViewTest { @Test public void testClientCertIssuersReceivedCorrectly() throws Throwable { - - startWebServer(new SharedSdkWebServer.Config() - .setSslMode(SslMode.NEEDS_CLIENT_AUTH) - .setAcceptedIssuer(FAKE_RSA_CA_1)); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.NEEDS_CLIENT_AUTH, + FAKE_RSA_CA_1, 0, 0); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final ClientCertWebViewClient webViewClient = new ClientCertWebViewClient(mOnUiThread); mOnUiThread.setWebViewClient(webViewClient); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java index e6499d063d0..f6c60018b31 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java @@ -216,12 +216,6 @@ public class WebViewTest extends SharedWebViewTest { return environment; } - private void startWebServer(boolean secure) throws Exception { - assertNull(mWebServer); - mWebServer = getTestEnvironment().getWebServer(); - mWebServer.start(secure ? SslMode.NO_CLIENT_AUTH : SslMode.INSECURE); - } - @Test public void testConstructor() { WebkitUtils.onMainThreadSync( @@ -325,7 +319,7 @@ public class WebViewTest extends SharedWebViewTest { @Test @Presubmit public void testLoadUrl() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -368,7 +362,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testPostUrlWithNetworkUrl() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String networkUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); final String postDataString = "username=my_username&password=my_password"; @@ -400,7 +394,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testAppInjectedXRequestedWithHeaderIsNotOverwritten() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -424,7 +418,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testAppCanInjectHeadersViaImmutableMap() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -453,7 +447,7 @@ public class WebViewTest extends SharedWebViewTest { final String X_REFERER = "Referer"; final String X_REFERER_VALUE = "http://www.example.com/"; - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); HashMap<String, String> map = new HashMap<String, String>(); map.put(X_FOO, X_FOO_VALUE); @@ -472,7 +466,7 @@ public class WebViewTest extends SharedWebViewTest { @Test @SuppressWarnings("deprecation") public void testGetVisibleTitleHeight() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -484,7 +478,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testGetOriginalUrl() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -512,7 +506,7 @@ public class WebViewTest extends SharedWebViewTest { public void testStopLoading() throws Exception { assertEquals(INITIAL_PROGRESS, mOnUiThread.getProgress()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getDelayedAssetUrl(TestHtmlConstants.STOP_LOADING_URL); class JsInterface { @@ -546,7 +540,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testGoBackAndForward() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -633,7 +627,7 @@ public class WebViewTest extends SharedWebViewTest { mOnUiThread.addJavascriptInterface(obj, "interface"); assertFalse(obj.wasProvideResultCalled()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.ADD_JAVA_SCRIPT_INTERFACE_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); assertEquals("Original title", obj.waitForResult()); @@ -839,7 +833,7 @@ public class WebViewTest extends SharedWebViewTest { } }); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.POPUP_URL)); WebkitUtils.waitForFuture(onCreateWindowFuture); @@ -891,7 +885,7 @@ public class WebViewTest extends SharedWebViewTest { public void testCapturePicture() throws Exception, Throwable { final TestPictureListener listener = new TestPictureListener(); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL); mOnUiThread.setPictureListener(listener); // Showing the blank page will fill the picture with the background color. @@ -930,7 +924,7 @@ public class WebViewTest extends SharedWebViewTest { } final MyPictureListener listener = new MyPictureListener(); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.setPictureListener(listener); mOnUiThread.loadUrlAndWaitForCompletion(url); @@ -1095,7 +1089,7 @@ public class WebViewTest extends SharedWebViewTest { mOnUiThread.loadDataAndWaitForCompletion(HTML_CONTENT, "text/html", null); assertEquals(firstTitle, mOnUiThread.getTitle()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.getSettings().setJavaScriptEnabled(true); final String secondTitle = "Foo bar"; @@ -1126,7 +1120,7 @@ public class WebViewTest extends SharedWebViewTest { // will fail and we won't make a request to the test web server. // By using the test web server as the base URL we expect to see a request // for the relative URL in the test server. - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String baseUrl = mWebServer.getAssetUrl("foo.html"); mWebServer.resetRequestState(); mOnUiThread.loadDataWithBaseURLAndWaitForCompletion( @@ -1163,7 +1157,7 @@ public class WebViewTest extends SharedWebViewTest { public void testLoadDataWithBaseUrl_javascriptCanAccessOrigin() throws Throwable { // Test that JavaScript can access content from the same origin as the base URL. mOnUiThread.getSettings().setJavaScriptEnabled(true); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String baseUrl = mWebServer.getAssetUrl("foo.html"); final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.loadDataWithBaseURLAndWaitForCompletion( @@ -1467,7 +1461,7 @@ public class WebViewTest extends SharedWebViewTest { } } - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.SMALL_IMG_URL); // Create a handler on the UI thread. @@ -1715,7 +1709,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testRequestFocusNodeHref() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1); final String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2); @@ -1802,7 +1796,7 @@ public class WebViewTest extends SharedWebViewTest { mOnUiThread.getSettings().setJavaScriptEnabled(true); mOnUiThread.addJavascriptInterface(imageLoaded, "imageLoaded"); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.LARGE_IMG_URL); mOnUiThread.loadDataAndWaitForCompletion( "<html><head><title>Title</title><style type='text/css'>" @@ -1993,7 +1987,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testClearHistory() throws Exception { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -2019,7 +2013,7 @@ public class WebViewTest extends SharedWebViewTest { @Test public void testSaveAndRestoreState() throws Throwable { - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); WebkitUtils.onMainThreadSync( () -> { @@ -2142,7 +2136,7 @@ public class WebViewTest extends SharedWebViewTest { final int length = 100; final MyDownloadListener listener = new MyDownloadListener(); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getBinaryUrl(mimeType, length); // By default, WebView sends an intent to ask the system to @@ -2187,7 +2181,7 @@ public class WebViewTest extends SharedWebViewTest { public void testSetNetworkAvailable() throws Exception { WebSettings settings = mOnUiThread.getSettings(); settings.setJavaScriptEnabled(true); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); String url = mWebServer.getAssetUrl(TestHtmlConstants.NETWORK_STATE_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); @@ -2228,7 +2222,7 @@ public class WebViewTest extends SharedWebViewTest { getTestEnvironment().waitForIdleSync(); assertFalse(future.isDone()); - startWebServer(false); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.INSECURE); final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL); mOnUiThread.loadUrlAndWaitForCompletion(url); getTestEnvironment().waitForIdleSync(); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTransportTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTransportTest.java index 612c603db26..1f159dcb321 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebViewTransportTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTransportTest.java @@ -29,33 +29,41 @@ import androidx.test.filters.MediumTest; import com.android.compatibility.common.util.NullWebViewUtils; import org.junit.Assume; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @MediumTest @RunWith(AndroidJUnit4.class) -public class WebViewTransportTest { +public class WebViewTransportTest extends SharedWebViewTest { @Rule public ActivityScenarioRule mActivityScenarioRule = new ActivityScenarioRule(WebViewCtsActivity.class); - private WebViewCtsActivity mActivity; - - @Before - public void setUp() throws Throwable { + @Override + protected SharedWebViewTestEnvironment createTestEnvironment() { Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable()); - mActivityScenarioRule.getScenario().onActivity(activity -> { - mActivity = (WebViewCtsActivity) activity; - }); + SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder(); + + mActivityScenarioRule + .getScenario() + .onActivity( + activity -> { + WebView webView = ((WebViewCtsActivity) activity).getWebView(); + builder.setHostAppInvoker( + SharedWebViewTestEnvironment.createHostAppInvoker( + activity)) + .setWebView(webView); + }); + + return builder.build(); } @Test public void testAccessWebView() { WebkitUtils.onMainThreadSync(() -> { - WebView webView = mActivity.getWebView(); + WebView webView = getTestEnvironment().getWebView(); WebViewTransport transport = webView.new WebViewTransport(); assertNull(transport.getWebView()); diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java index 84384d39609..6b8ea8de9f8 100644 --- a/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java +++ b/tests/tests/webkit/src/android/webkit/cts/WebViewZoomTest.java @@ -131,10 +131,9 @@ public class WebViewZoomTest extends SharedWebViewTest{ assertFalse("onScaleChanged has already been called before page has been setup", mWebViewClient.onScaleChangedCalled()); assertNull(mWebServer); - mWebServer = getTestEnvironment().getWebServer(); // Pass SslMode.TRUST_ANY_CLIENT to make the server serve https URLs yet do // not ask client for client authentication. - mWebServer.start(SslMode.TRUST_ANY_CLIENT); + mWebServer = getTestEnvironment().getSetupWebServer(SslMode.TRUST_ANY_CLIENT); mOnUiThread.loadUrlAndWaitForCompletion( mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL)); pollingCheckForCanZoomIn(); diff --git a/tests/tests/widget/res/layout/horizontal_scrollview.xml b/tests/tests/widget/res/layout/horizontal_scrollview.xml index c82472b0c1f..11ba673427c 100644 --- a/tests/tests/widget/res/layout/horizontal_scrollview.xml +++ b/tests/tests/widget/res/layout/horizontal_scrollview.xml @@ -22,89 +22,89 @@ <view class="android.widget.cts.HorizontalScrollViewTest$MyHorizontalScrollView" android:id="@+id/horizontal_scroll_view_custom" - android:layout_width="100px" - android:layout_height="100px"> + android:layout_width="200px" + android:layout_height="200px"> <LinearLayout android:orientation="horizontal" - android:layout_width="250px" + android:layout_width="500px" android:layout_height="wrap_content"> <Button android:id="@+id/first_horizontal_child" - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_1"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_2"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_3"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_1"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_2"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_3"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_1"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_2"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_3"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_1"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_2"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_3"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_1"/> <Button - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_2"/> <Button android:id="@+id/last_horizontal_child" - android:layout_width="250px" - android:layout_height="100px" + android:layout_width="500px" + android:layout_height="200px" android:text="@string/vertical_text_3"/> </LinearLayout> @@ -118,8 +118,8 @@ <view class="android.widget.cts.HorizontalScrollViewTest$MyHorizontalScrollView" android:id="@+id/horizontal_scroll_view_custom_empty" - android:layout_width="100px" - android:layout_height="100px" /> + android:layout_width="200px" + android:layout_height="200px" /> <view class="android.widget.cts.HorizontalScrollViewTest$InterceptView" @@ -128,8 +128,8 @@ android:layout_height="wrap_content"> <HorizontalScrollView android:id="@+id/horizontal_scroll_view_stretch" - android:layout_width="90px" - android:layout_height="90px" + android:layout_width="180px" + android:layout_height="180px" android:background="#FFF"> <LinearLayout android:layout_width="match_parent" @@ -137,28 +137,28 @@ android:orientation="horizontal"> <View android:background="#00F" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> <View android:background="#0FF" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> <View android:background="#0F0" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> <View android:background="#FF0" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> <View android:background="#F00" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> <View android:background="#F0F" - android:layout_width="50px" - android:layout_height="90px"/> + android:layout_width="100px" + android:layout_height="180px"/> </LinearLayout> </HorizontalScrollView> </view> diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java index 0067a8ab837..cf9bb246faf 100644 --- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java +++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java @@ -71,11 +71,11 @@ import java.util.ArrayList; @MediumTest @RunWith(AndroidJUnit4.class) public class HorizontalScrollViewTest { - private static final int ITEM_WIDTH = 250; - private static final int ITEM_HEIGHT = 100; + private static final int ITEM_WIDTH = 500; + private static final int ITEM_HEIGHT = 200; private static final int ITEM_COUNT = 15; - private static final int PAGE_WIDTH = 100; - private static final int PAGE_HEIGHT = 100; + private static final int PAGE_WIDTH = 200; + private static final int PAGE_HEIGHT = 200; private static final int SCROLL_RIGHT = ITEM_WIDTH * ITEM_COUNT - PAGE_WIDTH; private Instrumentation mInstrumentation; diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java index 000ae807d59..1f52b25ee32 100644 --- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java +++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java @@ -203,8 +203,6 @@ public class TextViewTest { } }; private static final int CLICK_TIMEOUT = ViewConfiguration.getDoubleTapTimeout() + 50; - private static final int BOLD_TEXT_ADJUSTMENT = - FontStyle.FONT_WEIGHT_BOLD - FontStyle.FONT_WEIGHT_NORMAL; private CharSequence mTransformedText; @@ -330,26 +328,32 @@ public class TextViewTest { @Test public void testFontWeightAdjustment_forceBoldTextEnabled_textIsBolded() throws Throwable { mActivityRule.runOnUiThread(() -> mTextView = findTextView(R.id.textview_text)); + final int defaultFontWeight = mTextView.getTypeface().getWeight(); mInstrumentation.waitForIdleSync(); - assertEquals(FontStyle.FONT_WEIGHT_NORMAL, mTextView.getTypeface().getWeight()); - Configuration cf = new Configuration(); - cf.fontWeightAdjustment = BOLD_TEXT_ADJUSTMENT; + final int fontWeightAdjustment = FontStyle.FONT_WEIGHT_BOLD - defaultFontWeight; + cf.fontWeightAdjustment = + fontWeightAdjustment <= 0 ? FontStyle.FONT_WEIGHT_MAX : fontWeightAdjustment; mActivityRule.runOnUiThread(() -> mTextView.dispatchConfigurationChanged(cf)); mInstrumentation.waitForIdleSync(); Typeface forceBoldedPaintTf = mTextView.getPaint().getTypeface(); assertEquals(FontStyle.FONT_WEIGHT_BOLD, forceBoldedPaintTf.getWeight()); - assertEquals(FontStyle.FONT_WEIGHT_NORMAL, mTextView.getTypeface().getWeight()); + assertEquals(defaultFontWeight, mTextView.getTypeface().getWeight()); } @Test public void testFontWeightAdjustment_forceBoldTextDisabled_textIsUnbolded() throws Throwable { + mActivityRule.runOnUiThread(() -> mTextView = findTextView(R.id.textview_text)); + final int defaultFontWeight = mTextView.getTypeface().getWeight(); + Configuration cf = new Configuration(); - cf.fontWeightAdjustment = BOLD_TEXT_ADJUSTMENT; + final int fontWeightAdjustment = FontStyle.FONT_WEIGHT_BOLD - defaultFontWeight; + cf.fontWeightAdjustment = + fontWeightAdjustment <= 0 ? FontStyle.FONT_WEIGHT_MAX : fontWeightAdjustment; + mActivityRule.runOnUiThread(() -> { - mTextView = findTextView(R.id.textview_text); mTextView.dispatchConfigurationChanged(cf); cf.fontWeightAdjustment = 0; mTextView.dispatchConfigurationChanged(cf); @@ -357,8 +361,8 @@ public class TextViewTest { mInstrumentation.waitForIdleSync(); Typeface forceUnboldedPaintTf = mTextView.getPaint().getTypeface(); - assertEquals(FontStyle.FONT_WEIGHT_NORMAL, forceUnboldedPaintTf.getWeight()); - assertEquals(FontStyle.FONT_WEIGHT_NORMAL, mTextView.getTypeface().getWeight()); + assertEquals(defaultFontWeight, forceUnboldedPaintTf.getWeight()); + assertEquals(defaultFontWeight, mTextView.getTypeface().getWeight()); } @Test @@ -367,7 +371,7 @@ public class TextViewTest { mActivityRule.runOnUiThread(() -> { mTextView = findTextView(R.id.textview_text); Configuration cf = new Configuration(); - cf.fontWeightAdjustment = BOLD_TEXT_ADJUSTMENT; + cf.fontWeightAdjustment = FontStyle.FONT_WEIGHT_BOLD - FontStyle.FONT_WEIGHT_NORMAL; mTextView.dispatchConfigurationChanged(cf); mTextView.setTypeface(Typeface.MONOSPACE); }); @@ -381,7 +385,6 @@ public class TextViewTest { FontStyle.FONT_WEIGHT_BOLD, false), forceBoldedPaintTf); } - @Test public void testFontWeightAdjustment_forceBoldTextDisabled_originalTypefaceIsKept() throws Throwable { @@ -405,7 +408,7 @@ public class TextViewTest { mActivityRule.runOnUiThread(() -> { mTextView = findTextView(R.id.textview_text); Configuration cf = new Configuration(); - cf.fontWeightAdjustment = BOLD_TEXT_ADJUSTMENT; + cf.fontWeightAdjustment = FontStyle.FONT_WEIGHT_BOLD - FontStyle.FONT_WEIGHT_NORMAL; mTextView.dispatchConfigurationChanged(cf); mTextView.setTypeface(originalTypeface); }); 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 4eecaf0ec28..864b31c6bf2 100644 --- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java @@ -18,6 +18,7 @@ package android.net.wifi.cts; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.wifi.SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD; import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP; import static android.net.wifi.WifiAvailableChannel.OP_MODE_STA; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; @@ -2742,6 +2743,10 @@ public class WifiManagerTest extends WifiJUnit3TestBase { () -> mWifiManager.isWifiEnabled() == true); turnOffWifiAndTetheredHotspotIfEnabled(); verifyRegisterSoftApCallback(executor, callback); + if (!callback.getCurrentSoftApCapability() + .areFeaturesSupported(SOFTAP_FEATURE_ACS_OFFLOAD)) { + return; + } int[] testBands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ}; int[] expectedBands = {SoftApConfiguration.BAND_2GHZ, diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed index 21b36ca8d45..3d57a11d0f7 100755 --- a/tools/cts-tradefed/etc/cts-tradefed +++ b/tools/cts-tradefed/etc/cts-tradefed @@ -41,9 +41,9 @@ checkPath adb checkPath java # check java version -JAVA_VERSION=$(java -version 2>&1 | grep -m 1 'version [ "]\(1\.8\|9\|11\).*[ "]') +JAVA_VERSION=$(java -version 2>&1 | grep -m 1 'version [ "]\(1\.8\|9\|11\|17\).*[ "]') if [ "${JAVA_VERSION}" == "" ]; then - echo "Wrong java version. 1.8, 9, or 11 is required." + echo "Wrong java version. 1.8, 9, 11 or 17 is required." exit fi diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml index b85626eb9da..4f6360f27ca 100644 --- a/tools/cts-tradefed/res/config/cts-known-failures.xml +++ b/tools/cts-tradefed/res/config/cts-known-failures.xml @@ -311,4 +311,7 @@ <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_match" /> <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_mismatch" /> <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_anydata" /> -</configuration>
\ No newline at end of file + + <!-- b/266101051--> + <option name="compatibility:exclude-filter" value="CtsGameServiceTestCases" /> +</configuration> diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/loading/CommonConfigLoadingTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/loading/CommonConfigLoadingTest.java index c4d65418376..36ee7344a23 100644 --- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/loading/CommonConfigLoadingTest.java +++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/loading/CommonConfigLoadingTest.java @@ -83,6 +83,7 @@ public class CommonConfigLoadingTest { "com.android.tradefed.testtype.HostTest", "com.android.tradefed.testtype.GTest", "com.android.tradefed.testtype.mobly.MoblyBinaryHostTest", + "com.android.tradefed.testtype.pandora.PtsBotTest", // VTS specific runners "com.android.tradefed.testtype.binary.KernelTargetTest", "com.android.tradefed.testtype.python.PythonBinaryHostTest", @@ -107,8 +108,11 @@ public class CommonConfigLoadingTest { RUNNER_EXCEPTION.add("repackaged.android.test.InstrumentationTestRunner"); // Used by a UiRendering scenario where an activity is persisted between tests RUNNER_EXCEPTION.add("android.uirendering.cts.runner.UiRenderingRunner"); + // Used to avoid crashing runner on -eng build due to Log.wtf() - b/216648699 + RUNNER_EXCEPTION.add("com.android.server.uwb.CustomTestRunner"); + RUNNER_EXCEPTION.add("com.android.server.wifi.CustomTestRunner"); } - + /** * Test that configuration shipped in Tradefed can be parsed. * -> Exclude deprecated ApkInstaller. |