summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-08-03 16:47:27 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-08-03 16:47:27 +0000
commit9f0cce6cbd3d64bc38ef2bc809361c76368991d3 (patch)
treeb8db9022db9b19e23e3a8d0a526048dc4b259018
parentfce89317433a29381d5c80fce650688514ce9842 (diff)
parent861169880ae87a7c389a5d44d5d3f74e882c006d (diff)
downloadcts-android13-mainline-go-tethering-release.tar.gz
Snap for 8902501 from 861169880ae87a7c389a5d44d5d3f74e882c006d to mainline-go-tethering-releaseaml_go_tet_330914010android13-mainline-go-tethering-release
Change-Id: Ibd1ee0a0823759115626ad6bd0c4f01fef2f8011
-rw-r--r--apps/CameraITS/config.yml6
-rw-r--r--apps/CameraITS/tests/its_base_test.py2
-rw-r--r--apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py9
-rw-r--r--apps/CameraITS/tests/scene1_2/test_param_shading_mode.py14
-rw-r--r--apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py2
-rw-r--r--apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py2
-rw-r--r--apps/CameraITS/tests/scene3/test_edge_enhancement.py11
-rw-r--r--apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py25
-rw-r--r--apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py12
-rw-r--r--apps/CameraITS/tests/scene6/test_zoom.py21
-rw-r--r--apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py4
-rw-r--r--apps/CameraITS/utils/video_processing_utils.py6
-rw-r--r--apps/CtsVerifier/AndroidManifest.xml270
-rw-r--r--apps/CtsVerifier/res/values/strings.xml1
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java9
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java160
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java4
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java187
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java6
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS3
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java4
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java4
-rw-r--r--common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java33
-rw-r--r--common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java12
-rw-r--r--common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java6
-rw-r--r--common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java255
-rw-r--r--hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java6
-rw-r--r--hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java20
-rw-r--r--hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java8
-rw-r--r--hostsidetests/scopedstorage/Android.bp8
-rw-r--r--hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java40
-rw-r--r--hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java11
-rw-r--r--hostsidetests/security/src/android/security/cts/SELinuxHostTest.java29
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java73
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml1
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp36
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml32
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java94
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java117
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java20
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java84
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java5
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java6
-rw-r--r--tests/app/app/assets/picture_800_by_600.pngbin0 -> 22715 bytes
-rw-r--r--tests/app/src/android/app/cts/NotificationTemplateTest.kt7
-rw-r--r--tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java55
-rw-r--r--tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java3
-rw-r--r--tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java15
-rw-r--r--tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java3
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java44
-rw-r--r--tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java14
-rw-r--r--tests/media/src/android/mediav2/cts/CodecInfoTest.java11
-rw-r--r--tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java7
-rw-r--r--tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java4
-rw-r--r--tests/tests/hardware/AndroidManifest.xml10
-rw-r--r--tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm311
-rw-r--r--tests/tests/hardware/res/raw/keyboard_layout_french.kcm336
-rw-r--r--tests/tests/hardware/res/raw/keyboard_layout_german.kcm333
-rw-r--r--tests/tests/hardware/res/xml/keyboard_layouts.xml31
-rw-r--r--tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java12
-rw-r--r--tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java8
-rw-r--r--tests/tests/media/common/src/android/media/cts/CodecState.java4
-rw-r--r--tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java6
-rw-r--r--tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java255
-rw-r--r--tests/tests/media/common/src/android/media/cts/TestUtils.java1
-rw-r--r--tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java1
-rw-r--r--tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java534
-rw-r--r--tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java1
-rw-r--r--tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java5
-rw-r--r--tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java7
-rw-r--r--tests/tests/os/src/android/os/cts/AppHibernationUtils.kt58
-rw-r--r--tests/tests/os/src/android/os/cts/AutoRevokeTest.kt66
-rw-r--r--tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt29
-rw-r--r--tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java34
-rw-r--r--tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java72
-rw-r--r--tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt3
-rw-r--r--tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt20
-rw-r--r--tests/tests/provider/OWNERS14
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20135.java67
-rw-r--r--tests/tests/systemui/Android.bp1
-rw-r--r--tests/tests/systemui/AndroidManifest.xml1
-rw-r--r--tests/tests/systemui/src/android/systemui/cts/LightBarTests.java36
-rw-r--r--tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java130
-rw-r--r--tests/tests/telephony/OWNERS19
-rw-r--r--tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java86
-rw-r--r--tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt5
-rw-r--r--tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java48
-rw-r--r--tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java1
89 files changed, 3277 insertions, 1116 deletions
diff --git a/apps/CameraITS/config.yml b/apps/CameraITS/config.yml
index 0ae754eb3be..b9b0ddf21ec 100644
--- a/apps/CameraITS/config.yml
+++ b/apps/CameraITS/config.yml
@@ -20,9 +20,9 @@ TestBeds:
# Test configuration for scenes[0:4, 6, _change]
Controllers:
AndroidDevice:
- - serial: <device_id>
+ - serial: <device_id> # quotes are needed if serial id is entirely numeric
label: dut
- - serial: <tablet_id>
+ - serial: <tablet_id> # quotes are needed if serial id is entirely numeric
label: tablet
TestParams:
brightness: 192
@@ -37,7 +37,7 @@ TestBeds:
# Test configuration for sensor_fusion/test_sensor_fusion.py
Controllers:
AndroidDevice:
- - serial: <device-id>
+ - serial: <device-id> # quotes are needed if serial id is entirely numeric
label: dut
TestParams:
fps: 30
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 9b29ab72365..daa55c651d3 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -52,6 +52,8 @@ NOT_YET_MANDATED = {
'sensor_fusion': [],
}
+logging.getLogger('matplotlib.font_manager').disabled = True
+
class ItsBaseTest(base_test.BaseTestClass):
"""Base test for CameraITS tests.
diff --git a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
index 7d8b9f2c11e..e407fd65899 100644
--- a/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
+++ b/apps/CameraITS/tests/scene1_1/test_ev_compensation_basic.py
@@ -71,7 +71,6 @@ class EvCompensationBasicTest(its_base_test.ItsBaseTest):
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
log_path = self.log_path
- debug = self.debug_mode
test_name_w_path = os.path.join(log_path, NAME)
# check SKIP conditions
@@ -113,11 +112,6 @@ class EvCompensationBasicTest(its_base_test.ItsBaseTest):
caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
luma_locked = []
for i, cap in enumerate(caps):
- if debug:
- img = image_processing_utils.convert_capture_to_rgb_image(
- cap, props)
- image_processing_utils.write_image(
- img, f'{test_name_w_path}_ev{ev}_frame{i}.jpg')
if cap['metadata']['android.control.aeState'] == LOCKED:
ev_meta = cap['metadata']['android.control.aeExposureCompensation']
logging.debug('cap EV compensation: %d', ev_meta)
@@ -132,7 +126,8 @@ class EvCompensationBasicTest(its_base_test.ItsBaseTest):
rel_tol=luma_locked_rtol):
raise AssertionError(f'AE locked lumas: {luma_locked}, '
f'RTOL: {luma_locked_rtol}')
- logging.debug('lumas in AE locked captures: %s', str(lumas))
+ logging.debug('lumas per frame ev %d: %s', ev, str(luma_locked))
+ logging.debug('mean lumas in AE locked captures: %s', str(lumas))
if caps[THRESH_CONVERGE_FOR_EV-1]['metadata'][
'android.control.aeState'] != LOCKED:
raise AssertionError(f'No AE lock by {THRESH_CONVERGE_FOR_EV} frame.')
diff --git a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
index e3143f40d71..7fffa722b4a 100644
--- a/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1_2/test_param_shading_mode.py
@@ -32,6 +32,7 @@ _NUM_SWITCH_LOOPS = 3
_SHADING_MODES = {0: 'LSC_OFF', 1: 'LSC_FAST', 2: 'LSC_HQ'}
_NUM_SHADING_MODES = len(_SHADING_MODES)
_THRESHOLD_DIFF_RATIO = 0.15
+_VGA_W, _VGA_H = 640, 480
def create_plots(shading_maps, reference_maps, num_map_gains, log_path):
@@ -76,9 +77,8 @@ class ParamShadingModeTest(its_base_test.ItsBaseTest):
Lens shading correction modes are OFF=0, FAST=1, and HQ=2.
- Uses smallest yuv size matching the aspect ratio of largest yuv size to
- reduce some USB bandwidth overhead since we are only looking at output
- metadata in this test.
+ Uses VGA sized captures to reduce some USB bandwidth overhead since we are
+ only looking at output metadata in this test.
First asserts all modes are supported. Then runs 2 captures.
@@ -118,13 +118,11 @@ class ParamShadingModeTest(its_base_test.ItsBaseTest):
% str(props.get('android.shading.availableModes')),
[*_SHADING_MODES])
- # get smallest matching fmt
+ # define fmt
mono_camera = camera_properties_utils.mono_camera(props)
cam.do_3a(mono_camera=mono_camera)
- largest_yuv_fmt = capture_request_utils.get_largest_yuv_format(props)
- largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
- cap_fmt = capture_request_utils.get_smallest_yuv_format(
- props, match_ar=largest_yuv_size)
+ cap_fmt = {'format': 'yuv', 'width': _VGA_W, 'height': _VGA_H}
+ logging.debug('Capture format: %s', str(cap_fmt))
# cap1
reference_maps = [[] for mode in range(_NUM_SHADING_MODES)]
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
index 658ec8b377e..cb5be2ae2aa 100644
--- a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
@@ -27,7 +27,7 @@ CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD = 600 # ms
class CameraLaunchSPerfClassTest(its_base_test.ItsBaseTest):
"""Test camera launch latency for S performance class as specified in CDD.
- [7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
+ [2.2.7.2/7.5/H-1-6] MUST have camera2 startup latency (open camera to first preview
frame) < 600ms as measured by the CTS camera PerformanceTest under ITS
lighting conditions (3000K) for both primary cameras.
"""
diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
index f56d34cd5cd..fb19f2fb7c2 100644
--- a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
+++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
@@ -27,7 +27,7 @@ JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD = 1000 # ms
class JpegCaptureSPerfClassTest(its_base_test.ItsBaseTest):
"""Test jpeg capture latency for S performance class as specified in CDD.
- [7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
+ [2.2.7.2/7.5/H-1-5] MUST have camera2 JPEG capture latency < 1000ms for 1080p
resolution as measured by the CTS camera PerformanceTest under ITS lighting
conditions (3000K) for both primary cameras.
"""
diff --git a/apps/CameraITS/tests/scene3/test_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
index c6a3bcbc878..c1b63c7a503 100644
--- a/apps/CameraITS/tests/scene3/test_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_edge_enhancement.py
@@ -67,17 +67,17 @@ def do_capture_and_determine_sharpness(
for n in range(NUM_SAMPLES):
cap = cam.do_capture(req, out_surface, repeat_request=req)
y, _, _ = image_processing_utils.convert_capture_to_planes(cap)
- chart.img = image_processing_utils.normalize_img(
- image_processing_utils.get_image_patch(
- y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ chart.img = image_processing_utils.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
if n == 0:
image_processing_utils.write_image(
chart.img, '%s_edge=%d.jpg' % (
os.path.join(log_path, NAME), edge_mode))
edge_mode_res = cap['metadata']['android.edge.mode']
sharpness_list.append(
- image_processing_utils.compute_image_sharpness(chart.img))
-
+ image_processing_utils.compute_image_sharpness(chart.img)*255)
+ logging.debug('edge mode: %d, sharpness values: %s',
+ edge_mode_res, sharpness_list)
return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -89,7 +89,6 @@ class EdgeEnhancementTest(its_base_test.ItsBaseTest):
"""
def test_edge_enhancement(self):
- logging.debug('Starting %s', NAME)
with its_session_utils.ItsSession(
device_id=self.dut.serial,
camera_id=self.camera_id,
diff --git a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
index c5e9b1974c3..d67ebe4366b 100644
--- a/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
+++ b/apps/CameraITS/tests/scene3/test_reprocess_edge_enhancement.py
@@ -107,16 +107,15 @@ def do_capture_and_determine_sharpness(
caps = cam.do_capture([req]*NUM_SAMPLES, [out_surface], reprocess_format)
for n in range(NUM_SAMPLES):
y, _, _ = image_processing_utils.convert_capture_to_planes(caps[n])
- chart.img = image_processing_utils.normalize_img(
- image_processing_utils.get_image_patch(
- y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm))
+ chart.img = image_processing_utils.get_image_patch(
+ y, chart.xnorm, chart.ynorm, chart.wnorm, chart.hnorm)
if n == 0:
image_processing_utils.write_image(
chart.img, '%s_reprocess_fmt_%s_edge=%d.jpg' % (
os.path.join(log_path, NAME), reprocess_format, edge_mode))
edge_mode_res = caps[n]['metadata']['android.edge.mode']
sharpness_list.append(
- image_processing_utils.compute_image_sharpness(chart.img))
+ image_processing_utils.compute_image_sharpness(chart.img)*255)
logging.debug('Sharpness list for edge mode %d: %s',
edge_mode, str(sharpness_list))
return {'edge_mode': edge_mode_res, 'sharpness': np.mean(sharpness_list)}
@@ -134,7 +133,6 @@ class ReprocessEdgeEnhancementTest(its_base_test.ItsBaseTest):
"""
def test_reprocess_edge_enhancement(self):
- logging.debug('Starting %s', NAME)
logging.debug('Edge modes: %s', str(EDGE_MODES))
with its_session_utils.ItsSession(
device_id=self.dut.serial,
@@ -179,9 +177,10 @@ class ReprocessEdgeEnhancementTest(its_base_test.ItsBaseTest):
# Initialize plot
pylab.figure('reprocess_result')
- pylab.title(NAME)
- pylab.xlabel('Edge Enhance Mode')
- pylab.ylabel('Sharpness')
+ pylab.suptitle(NAME)
+ pylab.title(str(EDGE_MODES))
+ pylab.xlabel('Edge Enhancement Mode')
+ pylab.ylabel('Image Sharpness')
pylab.xticks(EDGE_MODES_VALUES)
# Get the sharpness for each edge mode for regular requests
@@ -244,6 +243,7 @@ class ReprocessEdgeEnhancementTest(its_base_test.ItsBaseTest):
logging.debug('Check reprocess format: %s', reprocess_format)
check_edge_modes(sharpnesses_reprocess[reprocess_format])
+ # Check reprocessing doesn't make everyting worse
hq_div_off_reprocess = (
sharpnesses_reprocess[reprocess_format][EDGE_MODES['HQ']] /
sharpnesses_reprocess[reprocess_format][EDGE_MODES['OFF']])
@@ -251,11 +251,10 @@ class ReprocessEdgeEnhancementTest(its_base_test.ItsBaseTest):
sharpness_regular[EDGE_MODES['HQ']] /
sharpness_regular[EDGE_MODES['OFF']])
logging.debug('Verify reprocess HQ ~= reg HQ relative to OFF')
- if not math.isclose(hq_div_off_reprocess, hq_div_off_regular,
- rel_tol=SHARPNESS_RTOL):
- raise AssertionError(f'HQ/OFF_reprocess: {hq_div_off_reprocess:.4f}, '
- f'HQ/OFF_reg: {hq_div_off_regular:.4f}, '
- f'RTOL: {SHARPNESS_RTOL}')
+ if hq_div_off_reprocess < hq_div_off_regular*(1-SHARPNESS_RTOL):
+ raise AssertionError(
+ f'HQ/OFF_{reprocess_format}: {hq_div_off_reprocess:.4f}, '
+ f'HQ/OFF_reg: {hq_div_off_regular:.4f}, RTOL: {SHARPNESS_RTOL}')
if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
index ae1f315c3e4..c1e50bd561a 100644
--- a/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
+++ b/apps/CameraITS/tests/scene5/test_lens_shading_and_color_uniformity.py
@@ -146,6 +146,7 @@ class LensShadingAndColorUniformityTest(its_base_test.ItsBaseTest):
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
log_path = self.log_path
+ debug_mode = self.debug_mode
# Check SKIP conditions.
camera_properties_utils.skip_unless(
@@ -163,7 +164,16 @@ class LensShadingAndColorUniformityTest(its_base_test.ItsBaseTest):
req = capture_request_utils.auto_capture_request()
w, h = capture_request_utils.get_available_output_sizes('yuv', props)[0]
out_surface = {'format': 'yuv', 'width': w, 'height': h}
- cap = cam.do_capture(req, out_surface)
+ if debug_mode:
+ out_surfaces = [{'format': 'raw'}, out_surface]
+ cap_raw, cap = cam.do_capture(req, out_surfaces)
+ img_raw = image_processing_utils.convert_capture_to_rgb_image(
+ cap_raw, props=props)
+ image_processing_utils.write_image(img_raw, '%s_raw.png' % (
+ os.path.join(log_path, _NAME)), True)
+ logging.debug('Captured RAW %dx%d', img_raw.shape[1], img_raw.shape[0])
+ else:
+ cap = cam.do_capture(req, out_surface)
logging.debug('Captured YUV %dx%d', w, h)
# Get Y channel
img_y = image_processing_utils.convert_capture_to_planes(cap)[0]
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index d4fa21c3c29..c1f4dff1d6d 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -78,10 +78,6 @@ def get_test_tols_and_cap_size(cam, props, chart_distance, debug):
test_tols = {}
test_yuv_sizes = []
for i in physical_ids:
- min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
- focal_l = physical_props[i]['android.lens.info.availableFocalLengths'][0]
- logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f',
- i, min_fd, focal_l)
yuv_sizes = capture_request_utils.get_available_output_sizes(
'yuv', physical_props[i])
test_yuv_sizes.append(yuv_sizes)
@@ -89,13 +85,16 @@ def get_test_tols_and_cap_size(cam, props, chart_distance, debug):
logging.debug('cam[%s] yuv sizes: %s', i, str(yuv_sizes))
# determine if minimum focus distance is less than rig depth
- if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or # fixed focus
- 1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL):
- test_tols[focal_l] = (RADIUS_RTOL, OFFSET_RTOL)
- else:
- test_tols[focal_l] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
- logging.debug('loosening RTOL for cam[%s]: '
- 'min focus distance too large.', i)
+ min_fd = physical_props[i]['android.lens.info.minimumFocusDistance']
+ for fl in physical_props[i]['android.lens.info.availableFocalLengths']:
+ logging.debug('cam[%s] min_fd: %.3f (diopters), fl: %.2f', i, min_fd, fl)
+ if (math.isclose(min_fd, 0.0, rel_tol=1E-6) or # fixed focus
+ (1.0/min_fd < chart_distance_m*MIN_FOCUS_DIST_TOL)):
+ test_tols[fl] = (RADIUS_RTOL, OFFSET_RTOL)
+ else:
+ test_tols[fl] = (RADIUS_RTOL_MIN_FD, OFFSET_RTOL_MIN_FD)
+ logging.debug('loosening RTOL for cam[%s]: '
+ 'min focus distance too large.', i)
# find intersection of formats for max common format
common_sizes = list(set.intersection(*[set(list) for list in test_yuv_sizes]))
if debug:
diff --git a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
index c6b852c5378..e1909517dda 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_preview_stabilization.py
@@ -142,7 +142,9 @@ class PreviewStabilizationTest(its_base_test.ItsBaseTest):
# List of video resolutions to test
supported_preview_sizes = cam.get_supported_preview_sizes(self.camera_id)
- supported_preview_sizes.remove(video_processing_utils.QCIF_SIZE)
+ for size in video_processing_utils.LOW_RESOLUTION_SIZES:
+ if size in supported_preview_sizes:
+ supported_preview_sizes.remove(size)
logging.debug('Supported preview resolutions: %s',
supported_preview_sizes)
diff --git a/apps/CameraITS/utils/video_processing_utils.py b/apps/CameraITS/utils/video_processing_utils.py
index 98d930bc90b..5eab20c0742 100644
--- a/apps/CameraITS/utils/video_processing_utils.py
+++ b/apps/CameraITS/utils/video_processing_utils.py
@@ -33,7 +33,11 @@ ITS_SUPPORTED_QUALITIES = (
'LOW',
'VGA'
)
-QCIF_SIZE = '176x144'
+
+LOW_RESOLUTION_SIZES = (
+ '176x144',
+ '192x144',
+)
def extract_key_frames_from_video(log_path, video_file_name):
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index db1ca21c978..307e19907d4 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2053,6 +2053,9 @@
<meta-data android:name="test_required_features" android:value="android.hardware.wifi" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="7.4.5.2" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.ConnectivityManager#registerNetworkCallback|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getLinkProperties" />
</activity>
<activity android:name=".net.MultiNetworkConnectivityTestActivity"
@@ -2069,6 +2072,8 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.ConnectivityManager#getNetworkCapabilities|android.net.ConnectivityManager#getAllNetworks|android.net.ConnectivityManager#requestNetwork|android.net.ConnectivityManager#unregisterNetworkCallback|android.net.ConnectivityManager#getActiveNetwork|android.net.ConnectivityManager#getNetworkInfo|android.net.ConnectivityManager#reportNetworkConnectivity" />
</activity>
<activity android:name=".nfc.NfcTestActivity"
@@ -2828,6 +2833,16 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.hardware.Camera#getNumberOfCameras|
+ android.hardware.Camera#open|
+ android.hardware.Camera#startPreview|
+ android.hardware.Camera#stopPreview|
+ android.hardware.Camera#takePicture|
+ android.hardware.Camera#setParameters|
+ android.hardware.Camera#setDisplayOrientation|
+ android.hardware.Camera.Parameters#setHorizontalViewAngle|
+ android.hardware.Camera.Parameters#setVerticalViewAngle" />
</activity>
<activity
android:name=".camera.fov.DetermineFovActivity"
@@ -2837,6 +2852,11 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.media.ExifInterface#TAG_ORIENTATION|
+ android.media.ExifInterface#ORIENTATION_ROTATE_90|
+ android.media.ExifInterface#ORIENTATION_ROTATE_180|
+ android.media.ExifInterface#ORIENTATION_ROTATE_270" />
</activity>
<activity
android:name=".camera.fov.CalibrationPreferenceActivity"
@@ -2862,6 +2882,32 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.hardware.Camera#getParameters|
+ android.hardware.Camera#lock|
+ android.hardware.Camera#setDisplayOrientation|
+ android.hardware.Camera#setPreviewCallback|
+ android.hardware.Camera#setParameters|
+ android.hardware.Camera#setPreviewTexture|
+ android.hardware.Camera#startPreview|
+ android.hardware.Camera#stopPreview|
+ android.hardware.Camera#unlock|
+ android.media.MediaRecorder#prepare|
+ android.media.MediaRecorder#release|
+ android.media.MediaRecorder#reset|
+ android.media.MediaRecorder#setAudioEncoder|
+ android.media.MediaRecorder#setAudioSource|
+ android.media.MediaRecorder#setCamera|
+ android.media.MediaRecorder#setOnErrorListener|
+ android.media.MediaRecorder#setOutputFormat|
+ android.media.MediaRecorder#setOutputFile|
+ android.media.MediaRecorder#setProfile|
+ android.media.MediaRecorder#setVideoEncoder|
+ android.media.MediaRecorder#setVideoEncodingBitRate|
+ android.media.MediaRecorder#setVideoSize|
+ android.media.MediaRecorder#setVideoSource|
+ android.media.MediaRecorder#start|
+ android.media.MediaRecorder#stop" />
</activity>
<activity android:name=".camera.its.ItsTestActivity"
@@ -3089,6 +3135,7 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="2.2.3/3.8.3/H-0-1|3.8.3.1/C-1-5|3.8.3.1/C-3-1|3.8.3.1/C-3-2|3.8.3.2/C-0-1|3.8.3.2/C-0-2|3.8.3.2/C-1-1" />
</activity>
<activity android:name=".notifications.NotificationPrivacyVerifierActivity"
@@ -3103,6 +3150,7 @@
<meta-data android:name="test_excluded_features"
android:value="android.hardware.type.automotive" />
<meta-data android:name="display_mode" android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.3.1/C-1-4|2.2.3/3.8.10/H-1-1" />
</activity>
<activity android:name=".notifications.ShowWhenLockedActivity"
@@ -3153,6 +3201,7 @@
android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.3.3/C-1-1" />
</activity>
<activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -3167,6 +3216,7 @@
android:value="android.hardware.type.watch:android.software.leanback" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="2.2.3/3.8.4/H-1-1|3.8.3.3/C-1-1|3.8.3.3/C-1-3" />
</activity>
<activity android:name=".notifications.ToastVerifierActivity"
@@ -3179,6 +3229,8 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.widget.Toast#makeText" />
</activity>
<activity android:name=".notifications.BubblesVerifierActivity"
@@ -3193,6 +3245,8 @@
android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.app.Notification.Builder#setBubbleMetadata|android.app.NotificationManager#notify" />
</activity>
<activity android:name=".notifications.BubbleActivity"
@@ -3248,6 +3302,7 @@
android:value="android.hardware.type.watch:android.software.leanback:android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="CddTest" android:value="3.8.1/C-4-1" />
</activity>
<activity android:name=".qstiles.TileServiceVerifierActivity"
@@ -3464,6 +3519,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestPatternNetworkSpecifierTestActivity"
@@ -3471,6 +3534,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestUnavailableNetworkSpecifierTestActivity"
@@ -3478,6 +3549,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssidPattern
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkRequestInvalidCredentialNetworkSpecifierTestActivity"
@@ -3485,6 +3564,14 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSpecifier.Builder#build
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setSsid
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setBssid
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSpecifier.Builder#setWpa2Passphrase
+ |android.net.NetworkRequest.Builder#setNetworkSpecifier
+ |android.net.ConnectivityManager#requestNetwork" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidTestActivity"
@@ -3492,6 +3579,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidBssidTestActivity"
@@ -3499,6 +3599,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionSsidPostConnectTestActivity"
@@ -3506,6 +3619,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionConnectionFailureTestActivity"
@@ -3513,6 +3639,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".wifi.NetworkSuggestionModificationInPlaceTestActivity"
@@ -3520,6 +3659,19 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.WifiNetworkSuggestion.Builder#build
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setSsid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setBssid
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa2Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setWpa3Passphrase
+ |android.net.wifi.WifiNetworkSuggestion.Builder#setIsMetered
+ |android.net.wifi.WifiManager#addNetworkSuggestions
+ |android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener
+ |android.net.wifi.WifiManager#getNetworkSuggestions
+ |android.net.wifi.WifiManager#removeNetworkSuggestions
+ |android.net.wifi.WifiManager#removeSuggestionConnectionStatusListener
+ |android.net.wifi.WifiManager#addSuggestionConnectionStatusListener" />
</activity>
<activity android:name=".p2p.GoNegRequesterTestListActivity"
@@ -3683,6 +3835,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenPassiveSubscribeTestActivity"
@@ -3690,6 +3845,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenPassiveSubscribeAcceptAnyTestActivity"
@@ -3697,6 +3855,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishTestActivity"
@@ -3704,6 +3866,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeTestActivity"
@@ -3711,6 +3876,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeAcceptAnyTestActivity"
@@ -3718,6 +3887,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishTestActivity"
@@ -3725,6 +3898,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkPassiveSubscribeTestActivity"
@@ -3732,6 +3909,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkPassiveSubscribeAcceptAnyTestActivity"
@@ -3739,6 +3920,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
</activity>
<activity android:name=".wifiaware.DataPathOpenSolicitedPublishTestActivity"
@@ -3746,6 +3932,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenActiveSubscribeTestActivity"
@@ -3753,6 +3942,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathOpenActiveSubscribeAcceptAnyTestActivity"
@@ -3760,6 +3952,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishTestActivity"
@@ -3767,6 +3963,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeTestActivity"
@@ -3774,6 +3974,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeAcceptAnyTestActivity"
@@ -3781,6 +3985,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkSolicitedPublishTestActivity"
@@ -3788,6 +3997,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.PublishConfig.Builder#setPublishType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkActiveSubscribeTestActivity"
@@ -3795,6 +4008,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build" />
</activity>
<activity android:name=".wifiaware.DataPathPmkActiveSubscribeAcceptAnyTestActivity"
@@ -3802,6 +4019,11 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder" />
</activity>
<activity android:name=".wifiaware.DataPathOobOpenResponderTestActivity"
@@ -3809,6 +4031,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
</activity>
<activity android:name=".wifiaware.DataPathOobOpenInitiatorTestActivity"
@@ -3816,6 +4040,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen" />
</activity>
<activity android:name=".wifiaware.DataPathOobPassphraseResponderTestActivity"
@@ -3823,6 +4049,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathOobPassphraseInitiatorTestActivity"
@@ -3830,6 +4058,8 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase" />
</activity>
<activity android:name=".wifiaware.DiscoveryRangingPublishTestActivity"
@@ -3837,6 +4067,12 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+ |android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled
+ |android.net.wifi.rtt.WifiRttManager#startRanging
+ |android.net.wifi.aware.WifiAwareManager#attach
+ |android.net.wifi.aware.WifiAwareSession#publish" />
</activity>
<activity android:name=".wifiaware.DiscoveryRangingSubscribeTestActivity"
@@ -3844,6 +4080,12 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.rtt.RangingRequest.Builder#addWifiAwarePeer
+ |android.net.wifi.aware.SubscribeConfig.Builder#setMaxDistanceMm
+ |android.net.wifi.rtt.WifiRttManager#startRanging
+ |android.net.wifi.aware.WifiAwareManager#attach
+ |android.net.wifi.aware.WifiAwareSession#subscrible" />
</activity>
<activity android:name=".wifiaware.DataPathOpenSolicitedPublishAcceptAnyTestActivity"
@@ -3851,6 +4093,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
</activity>
<activity android:name=".wifiaware.DataPathPmkUnsolicitedPublishAcceptAnyTestActivity"
@@ -3858,6 +4104,10 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build
+ |android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE" />
</activity>
<activity android:name=".wifiaware.DataPathPmkSolicitedPublishAcceptAnyTestActivity"
@@ -3865,6 +4115,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishAcceptAnyTestActivity"
@@ -3872,6 +4125,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishAcceptAnyTestActivity"
@@ -3879,6 +4135,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathOpenUnsolicitedPublishAcceptAnyTestActivity"
@@ -3886,6 +4145,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase" />
</activity>
<activity android:name=".wifiaware.DataPathForceChannelSetupSubscribeTestActivity"
@@ -3893,6 +4155,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
</activity>
<activity android:name=".wifiaware.DataPathForceChannelSetupPublishTestActivity"
@@ -3900,6 +4165,9 @@
android:configChanges="keyboardHidden|orientation|screenSize" >
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#Builder
+ |android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setChannelFrequencyMhz" />
</activity>
<activity-alias
@@ -4808,6 +5076,8 @@
android:value="android.hardware.type.automotive" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback" />
</activity>
<activity android:name=".tv.TvInputDiscoveryTestActivity"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0f32b34e78e..b49337c8149 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -311,6 +311,7 @@
</string>
<string name="clipboard_preview_test_instructions">
Press the \'Copy\' button to copy the secret code to the clipboard.
+ \nDo not press any other buttons after you press the \'Copy\' button.
\n\n If nothing happens, press Fail.
\n\n If you see the word "FAIL" appear on screen, press Fail.
\n\n If you see a confirmation that content has been copied to the clipboard, press Pass.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 7b993eefc58..36975c251d7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -142,13 +142,13 @@ public class PassFailButtons {
public static class Activity extends android.app.Activity implements PassFailActivity {
private WakeLock mWakeLock;
- private final CtsVerifierReportLog mReportLog;
+ private CtsVerifierReportLog mReportLog;
private final TestResultHistoryCollection mHistoryCollection;
protected boolean mRequireReportLogToPass;
public Activity() {
- this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
+ newReportLog();
this.mHistoryCollection = new TestResultHistoryCollection();
}
@@ -211,6 +211,11 @@ public class PassFailButtons {
getHistoryCollection());
}
+ protected CtsVerifierReportLog newReportLog() {
+ return mReportLog = new CtsVerifierReportLog(
+ getReportFileName(), getReportSectionName());
+ }
+
@Override
public CtsVerifierReportLog getReportLog() {
return mReportLog;
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 79d3e3b2b0b..413734bdaad 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -127,11 +127,11 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
private TestSpec[] mTestSpecs = new TestSpec[NUM_TEST_ROUTES];
class TestSpec {
+ private static final String TAG = "AudioLoopbackLatencyActivity.TestSpec";
// impossibly low latencies (indicating something in the test went wrong).
protected static final double LOWEST_REASONABLE_LATENCY_MILLIS = 1.0;
final int mRouteId;
- // final double mMustLatencyMS;
// runtime assigned device ID
static final int DEVICEID_NONE = -1;
@@ -151,7 +151,6 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
boolean mRouteAvailable; // Have we seen this route/device at any time
boolean mRouteConnected; // is the route available NOW
boolean mTestRun;
- // boolean mTestPass;
TestSpec(int routeId, double requiredConfidence) {
mRouteId = routeId;
@@ -181,14 +180,6 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
mMeanConfidence = StatUtils.calculateMean(mConfidence);
}
- boolean getRouteAvailable() {
- return mRouteAvailable;
- }
-
- boolean getTestRun() {
- return mTestRun;
- }
-
boolean isMeasurementValid() {
return mTestRun && mMeanLatencyMS > 1.0 && mMeanConfidence >= mRequiredConfidence;
}
@@ -224,60 +215,42 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
}
// ReportLog Schema (per route)
- private static final String KEY_ROUTEAVAILABLE = "route_available";
- private static final String KEY_ROUTECONNECTED = "route_connected";
- private static final String KEY_ROUTERUN = "route_run";
- private static final String KEY_LATENCY = "route_latency";
- private static final String KEY_CONFIDENCE = "route_confidence";
- private static final String KEY_MEANABSDEVIATION = "route_mean_absolute_deviation";
- private static final String KEY_IS_PERIPHERAL_ATTACHED = "route_is_peripheral_attached";
- private static final String KEY_INPUT_PERIPHERAL_NAME = "route_input_peripheral";
- private static final String KEY_OUTPUT_PERIPHERAL_NAME = "route_output_peripheral";
- private static final String KEY_TEST_PERIPHERAL = "route_test_peripheral";
-
- String makeSectionKey(String key) {
- return Integer.toString(mRouteId) + "_" + key;
- }
+ private static final String KEY_ROUTEINDEX = "route_index";
+ private static final String KEY_LATENCY = "latency";
+ private static final String KEY_CONFIDENCE = "confidence";
+ private static final String KEY_MEANABSDEVIATION = "mean_absolute_deviation";
+ private static final String KEY_IS_PERIPHERAL_ATTACHED = "is_peripheral_attached";
+ private static final String KEY_INPUT_PERIPHERAL_NAME = "input_peripheral";
+ private static final String KEY_OUTPUT_PERIPHERAL_NAME = "output_peripheral";
+ private static final String KEY_TEST_PERIPHERAL = "test_peripheral";
void recordTestResults(CtsVerifierReportLog reportLog) {
reportLog.addValue(
- makeSectionKey(KEY_ROUTEAVAILABLE),
- mRouteAvailable ? 1 : 0,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- makeSectionKey(KEY_ROUTECONNECTED),
- mRouteConnected ? 1 : 0,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- makeSectionKey(KEY_ROUTERUN),
- mTestRun ? 1 : 0,
+ KEY_ROUTEINDEX,
+ mRouteId,
ResultType.NEUTRAL,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_LATENCY),
+ KEY_LATENCY,
mMeanLatencyMS,
ResultType.LOWER_BETTER,
ResultUnit.MS);
reportLog.addValue(
- makeSectionKey(KEY_CONFIDENCE),
+ KEY_CONFIDENCE,
mMeanConfidence,
ResultType.HIGHER_BETTER,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_MEANABSDEVIATION),
+ KEY_MEANABSDEVIATION,
mMeanAbsoluteDeviation,
ResultType.NEUTRAL,
ResultUnit.NONE);
reportLog.addValue(
- makeSectionKey(KEY_TEST_PERIPHERAL),
+ KEY_TEST_PERIPHERAL,
mDeviceName,
ResultType.NEUTRAL,
ResultUnit.NONE);
@@ -476,7 +449,6 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
mTestSpecs[TESTROUTE_USB].mDeviceName = devInfo.getProductName().toString();
}
- // setTestButtonsState();
enableStartButtons(true);
}
}
@@ -535,69 +507,66 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
return setTestNameSuffix(sCurrentDisplayMode, "audio_loopback_latency_activity");
}
- // Schema
+ // Test-Schema
private static final String KEY_SAMPLE_RATE = "sample_rate";
private static final String KEY_IS_PRO_AUDIO = "is_pro_audio";
private static final String KEY_IS_LOW_LATENCY = "is_low_latency";
private static final String KEY_TEST_MMAP = "supports_mmap";
private static final String KEY_TEST_MMAPEXCLUSIVE = "supports_mmap_exclusive";
private static final String KEY_LEVEL = "level";
- //
- // Subclasses should call this explicitly. SubClasses should call submit() after their logs
- //
- @Override
- public void recordTestResults() {
- Log.i(TAG, "recordTestResults() mNativeAnalyzerThread:" + mNativeAnalyzerThread);
-
- // We need to rework that
- CtsVerifierReportLog reportLog = getReportLog();
-
- int audioLevel = mAudioLevelSeekbar.getProgress();
- reportLog.addValue(
- KEY_LEVEL,
- audioLevel,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_IS_PRO_AUDIO,
- mClaimsProAudio,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_TEST_MMAP,
- mSupportsMMAP,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- reportLog.addValue(
- KEY_TEST_MMAPEXCLUSIVE ,
- mSupportsMMAPExclusive,
- ResultType.NEUTRAL,
- ResultUnit.NONE);
-
- if (mNativeAnalyzerThread == null) {
- return; // no test results to report
- }
- reportLog.addValue(
- KEY_SAMPLE_RATE,
- mNativeAnalyzerThread.getSampleRate(),
- ResultType.NEUTRAL,
- ResultUnit.NONE);
+ private void recordRouteResults(int routeIndex) {
+ if (mTestSpecs[routeIndex].mTestRun) {
+ CtsVerifierReportLog reportLog = newReportLog();
- reportLog.addValue(
- KEY_IS_LOW_LATENCY,
- mNativeAnalyzerThread.isLowLatencyStream(),
- ResultType.NEUTRAL,
- ResultUnit.NONE);
+ int audioLevel = mAudioLevelSeekbar.getProgress();
+ reportLog.addValue(
+ KEY_LEVEL,
+ audioLevel,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
- for (TestSpec testSpec : mTestSpecs) {
- testSpec.recordTestResults(reportLog);
+ reportLog.addValue(
+ KEY_IS_PRO_AUDIO,
+ mClaimsProAudio,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_TEST_MMAP,
+ mSupportsMMAP,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_TEST_MMAPEXCLUSIVE,
+ mSupportsMMAPExclusive,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_SAMPLE_RATE,
+ mNativeAnalyzerThread.getSampleRate(),
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ reportLog.addValue(
+ KEY_IS_LOW_LATENCY,
+ mNativeAnalyzerThread.isLowLatencyStream(),
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ mTestSpecs[routeIndex].recordTestResults(reportLog);
+
+ reportLog.submit();
}
+ }
- reportLog.submit();
+ @Override
+ public void recordTestResults() {
+ for (int route = 0; route < NUM_TEST_ROUTES; route++) {
+ recordRouteResults(route);
+ }
}
private void startAudioTest(Handler messageHandler, int testRouteId) {
@@ -660,6 +629,7 @@ public class AudioLoopbackLatencyActivity extends PassFailButtons.Activity {
e.printStackTrace();
}
+
mTestPhase++;
if (mTestPhase >= NUM_TEST_PHASES) {
handleTestCompletion();
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 212f988d205..106bd0b2ab6 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
@@ -1036,7 +1036,9 @@ public class ItsService extends Service implements SensorEventListener {
@Override
public void onImageAvailable(ImageReader reader) {
Image i = reader.acquireNextImage();
- i.close();
+ if (i != null) {
+ i.close();
+ }
}
};
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
index ff12bd23e16..171d612ce7d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
@@ -54,15 +54,18 @@ public class ReadLogsTestActivity extends PassFailButtons.Activity {
*/
private static final String TAG = "ReadLogsTestActivity";
- private static final String PERMISSION = "android.permission.READ_LOGS";
-
- private static final String ALLOW_LOGD_ACCESS = "Allow logd access";
- private static final String DENY_LOGD_ACCESS = "Decline logd access";
private static final String SYSTEM_LOG_START = "--------- beginning of system";
private static final int NUM_OF_LINES_FG = 10;
private static final int NUM_OF_LINES_BG = 0;
- private static final int LOG_ACCESS_INTERVAL = 1000 * 60 * 2;
+ private static final int LOG_ACCESS_INTERVAL_MILLIS = 1000 * 60 * 2;
+
+ private static final List<String> LOG_CAT_TEST_COMMAND = Arrays.asList("logcat",
+ "-b", "system",
+ "-v", "uid",
+ "-v", "process",
+ "-t", Integer.toString(NUM_OF_LINES_FG));
+
private volatile long mLastLogAccess = 0;
private static Context sContext;
@@ -71,11 +74,14 @@ public class ReadLogsTestActivity extends PassFailButtons.Activity {
private static String sAppPackageName;
private static ExecutorService sExecutorService;
+ private static String sLogCatUidFilterRegex;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this;
+ sLogCatUidFilterRegex = "^[A-Z]{1}\\(\\s" + sContext.getApplicationInfo().uid;
sActivityManager = sContext.getSystemService(ActivityManager.class);
sExecutorService = Executors.newSingleThreadExecutor();
@@ -114,72 +120,70 @@ public class ReadLogsTestActivity extends PassFailButtons.Activity {
public void runLogcatInForegroundAllowOnlyOnce() {
Log.d(TAG, "Inside runLogcatInForegroundAllowOnlyOnce()");
- if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
String reason = "Please wait for "
- + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
/ 1000) + " seconds before running the test.";
Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
return;
}
- sExecutorService.execute(new Runnable() {
-
- public void run() {
- BufferedReader reader = null;
- try {
-
- // Dump the logcat most recent 10 lines before the compile command,
- // and check if there are logs about compiling the test package.
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- logcat.waitFor();
-
- List<String> logcatOutput = new ArrayList<>();
- String current;
- Integer lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
- }
+ sExecutorService.execute(() -> {
+ BufferedReader reader = null;
+ try {
+
+ // Dump the logcat most recent 10 lines before the compile command,
+ // and check if there are logs about compiling the test package.
+ Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ logcat.waitFor();
+
+ List<String> logcatOutput = new ArrayList<>();
+ String current;
+ Integer lineCount = 0;
+ while ((current = reader.readLine()) != null) {
+ logcatOutput.add(current);
+ lineCount++;
+ }
- Log.d(TAG, "Logcat system allow line count: " + lineCount);
- Log.d(TAG, "Logcat system allow output: " + logcatOutput);
+ Log.d(TAG, "Logcat system allow line count: " + lineCount);
+ Log.d(TAG, "Logcat system allow output: " + logcatOutput);
- try {
+ try {
+ assertTrue("System log output is null", logcatOutput.size() != 0);
- assertTrue("System log output is null", logcatOutput.size() != 0);
+ // Check if the logcatOutput is not null. If logcatOutput is null,
+ // it throws an assertion error
+ assertNotNull(logcatOutput.get(0), "logcat output should not be null");
- // Check if the logcatOutput is not null. If logcatOutput is null,
- // it throws an assertion error
- assertNotNull(logcatOutput.get(0), "logcat output should not be null");
+ boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
+ assertTrue("Allow system log access contains log", allowLog);
- boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
- assertTrue("Allow system log access containe log", allowLog);
+ boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
+ assertTrue("Allow system log access count", allowLineCount);
- boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
- assertTrue("Allow system log access count", allowLineCount);
+ Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
+ + lineCount + " larger than: " + allowLineCount);
- Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
- + lineCount + " larger than: " + allowLineCount);
+ mLastLogAccess = SystemClock.elapsedRealtime();
- mLastLogAccess = SystemClock.elapsedRealtime();
+ runOnUiThread(() ->
+ Toast.makeText(this, "User Consent Allow Testing passed",
+ Toast.LENGTH_LONG).show());
- } catch (AssertionError e) {
- fail("User Consent Allow Testing failed");
- }
+ } catch (AssertionError e) {
+ fail("User Consent Allow Testing failed");
+ }
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
}
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
}
}
});
@@ -199,56 +203,53 @@ public class ReadLogsTestActivity extends PassFailButtons.Activity {
public void runLogcatInForegroundDontAllow() {
Log.d(TAG, "Inside runLogcatInForegroundDontAllow()");
- if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL_MILLIS)) {
String reason = "Please wait for "
- + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL_MILLIS - SystemClock.elapsedRealtime())
/ 1000) + " seconds before running the test.";
Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
return;
}
- sExecutorService.execute(new Runnable() {
+ sExecutorService.execute(() -> {
+ BufferedReader reader = null;
+ try {
+ Process logcat = new ProcessBuilder(LOG_CAT_TEST_COMMAND).start();
+ logcat.waitFor();
+
+ // Merge several logcat streams, and take the last N lines
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ assertNotNull(reader);
+
+ String current;
+ int lineCount = 0;
+ while ((current = reader.readLine()) != null
+ && current.matches(sLogCatUidFilterRegex)) {
+ lineCount++;
+ }
- public void run() {
- BufferedReader reader = null;
- try {
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- logcat.waitFor();
-
- // Merge several logcat streams, and take the last N lines
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- assertNotNull(reader);
-
- List<String> logcatOutput = new ArrayList<>();
- String current;
- int lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
- }
+ Log.d(TAG, "Logcat system deny line count:" + lineCount);
- Log.d(TAG, "Logcat system deny line count:" + lineCount);
+ mLastLogAccess = SystemClock.elapsedRealtime();
- mLastLogAccess = SystemClock.elapsedRealtime();
-
- try {
- assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
- } catch (AssertionError e) {
- fail("User Consent Deny Testing failed");
- }
+ try {
+ assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
+ runOnUiThread(() ->
+ Toast.makeText(this, "User Consent Deny Testing passed",
+ Toast.LENGTH_LONG).show());
+ } catch (AssertionError e) {
+ fail("User Consent Deny Testing failed");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
}
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
}
}
});
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
index 055f26f7af6..c0df10c996e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/MediaCodecFlushActivity.java
@@ -66,9 +66,9 @@ public class MediaCodecFlushActivity extends PassFailButtons.Activity {
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
- mPlayer.startThread();
+ mPlayer.startCodec();
+ mPlayer.play();
mHandler.postDelayed(this::pauseStep, 5000);
} catch(Exception e) {
Log.d(TAG, "Could not play video", e);
@@ -95,7 +95,7 @@ public class MediaCodecFlushActivity extends PassFailButtons.Activity {
private void resumeStep() {
try {
- mPlayer.start();
+ mPlayer.resume();
mHandler.postDelayed(this::enablePassButton, 3000);
} catch(Exception e) {
Log.d(TAG, "Could not resume video", e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
new file mode 100644
index 00000000000..4744ab89f6b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/OWNERS
@@ -0,0 +1,3 @@
+# Buganizer component id: 687598
+blindahl@google.com
+narcisaam@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
index 0163c62fcf1..c4461431b59 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tunnelmode/VolumeLevelChangesActivity.java
@@ -209,10 +209,10 @@ public class VolumeLevelChangesActivity extends PassFailButtons.Activity {
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
+ mPlayer.startCodec();
mPlayer.setLoopEnabled(true);
- mPlayer.startThread();
+ mPlayer.play();
} catch (Exception e) {
Log.d(TAG, "Could not play the video.", e);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
index 641ab20846f..94ef5363424 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/ModeSwitchingTestActivity.java
@@ -221,10 +221,10 @@ public class ModeSwitchingTestActivity extends PassFailButtons.Activity {
private void playVideo() {
try {
- mPlayer.start();
mPlayer.prepare();
+ mPlayer.startCodec();
mPlayer.setLoopEnabled(true);
- mPlayer.startThread();
+ mPlayer.play();
} catch (Exception e) {
Log.d(TAG, "Could not play video", e);
}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
new file mode 100644
index 00000000000..03d21f43d2a
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/RequireMultiUserSupport.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test requires multi-user support.
+ *
+ * <p>This can be enforced by using {@code DeviceState}.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+//@Experimental
+public @interface RequireMultiUserSupport {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index b28b815a9de..7bd649dc895 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -67,6 +67,7 @@ import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.RequireHeadlessSystemUserMode;
import com.android.bedstead.harrier.annotations.RequireLowRamDevice;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireNotHeadlessSystemUserMode;
import com.android.bedstead.harrier.annotations.RequireNotLowRamDevice;
import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
@@ -786,6 +787,12 @@ public final class DeviceState extends HarrierRule {
ensureGlobalSettingSet(
ensureGlobalSettingSetAnnotation.key(),
ensureGlobalSettingSetAnnotation.value());
+ continue;
+ }
+
+ if (annotation instanceof RequireMultiUserSupport) {
+ requireMultiUserSupport();
+ continue;
}
}
@@ -2528,4 +2535,9 @@ public final class DeviceState extends HarrierRule {
}
TestApis.settings().global().putString(key, value);
}
+
+ private void requireMultiUserSupport() {
+ assumeTrue("This test is only supported on multi user devices",
+ TestApis.users().supportsMultipleUsers());
+ }
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 200feb70b24..0ce2d7fe2e8 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -40,6 +40,7 @@ import androidx.annotation.CheckResult;
import androidx.annotation.Nullable;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.annotations.Experimental;
import com.android.bedstead.nene.exceptions.AdbException;
import com.android.bedstead.nene.exceptions.AdbParseException;
import com.android.bedstead.nene.exceptions.NeneException;
@@ -485,6 +486,11 @@ public final class Users {
return mCachedUsers.get(id);
}
+ @Experimental
+ public boolean supportsMultipleUsers() {
+ return UserManager.supportsMultipleUsers();
+ }
+
static Stream<UserInfo> users() {
if (Permissions.sIgnorePermissions.get()) {
return sUserManager.getUsers(
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
index ff389a118f5..4e798df6a5e 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/GestureNavRule.java
@@ -19,17 +19,15 @@ package com.android.compatibility.common.util;
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.SystemClock;
import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.ArrayMap;
+import android.view.WindowInsets;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
@@ -37,33 +35,31 @@ import org.junit.ClassRule;
import org.junit.rules.ExternalResource;
import java.io.IOException;
-import java.util.Map;
/**
* Test rule to enable gesture navigation on the device. Designed to be a {@link ClassRule}.
*/
public class GestureNavRule extends ExternalResource {
- private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
- private static final int NAV_BAR_INTERACTION_MODE_GESTURAL = 2;
+ private static final int NAV_BAR_MODE_3BUTTON = 0;
+ private static final int NAV_BAR_MODE_2BUTTON = 1;
+ private static final int NAV_BAR_MODE_GESTURAL = 2;
+
+ private static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
+ "com.android.internal.systemui.navbar.threebutton";
+ private static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
+ "com.android.internal.systemui.navbar.twobutton";
private static final String GESTURAL_OVERLAY_NAME =
"com.android.internal.systemui.navbar.gestural";
- /** Most application's res id must be larger than 0x7f000000 */
- public static final int MIN_APPLICATION_RES_ID = 0x7f000000;
- public static final String SETTINGS_CLASS =
- SETTINGS_PACKAGE_NAME + ".Settings$SystemDashboardActivity";
+ private static final int WAIT_OVERLAY_TIMEOUT = 3000;
+ private static final int PEEK_INTERVAL = 200;
- private final Map<String, Boolean> mSystemGestureOptionsMap = new ArrayMap<>();
private final Context mTargetContext;
private final UiDevice mDevice;
+ private final WindowManager mWindowManager;
- // Bounds for actions like swipe and click.
- private String mEdgeToEdgeNavigationTitle;
- private String mSystemNavigationTitle;
- private String mGesturePreferenceTitle;
- private boolean mConfiguredInSettings;
- private boolean mRevertOverlay;
+ private final String mOriginalOverlayPackage;
@Override
protected void before() throws Throwable {
@@ -74,7 +70,9 @@ public class GestureNavRule extends ExternalResource {
@Override
protected void after() {
- disableGestureNav();
+ if (!mOriginalOverlayPackage.equals(GESTURAL_OVERLAY_NAME)) {
+ disableGestureNav();
+ }
}
/**
@@ -85,39 +83,16 @@ public class GestureNavRule extends ExternalResource {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
mTargetContext = instrumentation.getTargetContext();
- PackageManager packageManager = mTargetContext.getPackageManager();
- Resources res;
- try {
- res = packageManager.getResourcesForApplication(SETTINGS_PACKAGE_NAME);
- } catch (PackageManager.NameNotFoundException e) {
- return;
- }
- if (res == null) {
- return;
- }
-
- mEdgeToEdgeNavigationTitle = getSettingsString(res, "edge_to_edge_navigation_title");
- mGesturePreferenceTitle = getSettingsString(res, "gesture_preference_title");
- mSystemNavigationTitle = getSettingsString(res, "system_navigation_title");
- String text = getSettingsString(res, "edge_to_edge_navigation_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
- text = getSettingsString(res, "swipe_up_to_switch_apps_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
- text = getSettingsString(res, "legacy_navigation_title");
- if (text != null) {
- mSystemGestureOptionsMap.put(text, false);
- }
-
- mConfiguredInSettings = false;
+ mOriginalOverlayPackage = getCurrentOverlayPackage();
+ mWindowManager = mTargetContext.getSystemService(WindowManager.class);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean hasSystemGestureFeature() {
+ if (!containsNavigationBar()) {
+ return false;
+ }
final PackageManager pm = mTargetContext.getPackageManager();
// No bars on embedded devices.
@@ -128,59 +103,21 @@ public class GestureNavRule extends ExternalResource {
|| pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
}
-
- private UiObject2 findSystemNavigationObject(String text, boolean addCheckSelector) {
- BySelector widgetFrameSelector = By.res("android", "widget_frame");
- BySelector checkboxSelector = By.checkable(true);
- if (addCheckSelector) {
- checkboxSelector = checkboxSelector.checked(true);
+ private String getCurrentOverlayPackage() {
+ final int currentNavMode = getCurrentNavMode();
+ switch (currentNavMode) {
+ case NAV_BAR_MODE_GESTURAL:
+ return GESTURAL_OVERLAY_NAME;
+ case NAV_BAR_MODE_2BUTTON:
+ return NAV_BAR_MODE_2BUTTON_OVERLAY;
+ case NAV_BAR_MODE_3BUTTON:
+ default:
+ return NAV_BAR_MODE_3BUTTON_OVERLAY;
}
- BySelector textSelector = By.text(text);
- BySelector targetSelector = By.hasChild(widgetFrameSelector).hasDescendant(textSelector)
- .hasDescendant(checkboxSelector);
-
- return mDevice.findObject(targetSelector);
}
- private boolean launchToSettingsSystemGesture() {
-
- // Open the Settings app as close as possible to the gesture Fragment
- Intent intent = new Intent(Intent.ACTION_MAIN);
- ComponentName settingComponent = new ComponentName(SETTINGS_PACKAGE_NAME, SETTINGS_CLASS);
- intent.setComponent(settingComponent);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mTargetContext.startActivity(intent);
-
- // Wait for the app to appear
- mDevice.wait(Until.hasObject(By.pkg("com.android.settings").depth(0)),
- 5000);
- mDevice.wait(Until.hasObject(By.text(mGesturePreferenceTitle)), 5000);
- if (mDevice.findObject(By.text(mGesturePreferenceTitle)) == null) {
- return false;
- }
- mDevice.findObject(By.text(mGesturePreferenceTitle)).click();
- mDevice.wait(Until.hasObject(By.text(mSystemNavigationTitle)), 5000);
- if (mDevice.findObject(By.text(mSystemNavigationTitle)) == null) {
- return false;
- }
- mDevice.findObject(By.text(mSystemNavigationTitle)).click();
- mDevice.wait(Until.hasObject(By.text(mEdgeToEdgeNavigationTitle)), 5000);
-
- return mDevice.hasObject(By.text(mEdgeToEdgeNavigationTitle));
- }
-
- private void leaveSettings() {
- mDevice.pressBack(); /* Back to Gesture */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* Back to System */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* back to Settings */
- mDevice.waitForIdle();
- mDevice.pressBack(); /* Back to Home */
- mDevice.waitForIdle();
-
- mDevice.pressHome(); /* double confirm back to home */
- mDevice.waitForIdle();
+ private void insetsToRect(Insets insets, Rect outRect) {
+ outRect.set(insets.left, insets.top, insets.right, insets.bottom);
}
private void enableGestureNav() {
@@ -188,71 +125,68 @@ public class GestureNavRule extends ExternalResource {
return;
}
try {
- if (mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
- mDevice.executeShellCommand("cmd overlay enable " + GESTURAL_OVERLAY_NAME);
- mDevice.waitForIdle();
+ if (!mDevice.executeShellCommand("cmd overlay list").contains(GESTURAL_OVERLAY_NAME)) {
+ return;
}
- } catch (IOException e) {
- // Do nothing
+ } catch (IOException ignore) {
+ //
}
-
- if (isGestureMode()) {
- mRevertOverlay = true;
- return;
- }
-
- // Set up the gesture navigation by enabling it via the Settings app
- boolean isOperatedSettingsToExpectedOption = launchToSettingsSystemGesture();
- if (isOperatedSettingsToExpectedOption) {
- for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
- UiObject2 uiObject2 = findSystemNavigationObject(entry.getKey(), true);
- entry.setValue(uiObject2 != null);
- }
- UiObject2 edgeToEdgeObj = mDevice.findObject(By.text(mEdgeToEdgeNavigationTitle));
- if (edgeToEdgeObj != null) {
- edgeToEdgeObj.click();
- mConfiguredInSettings = true;
+ monitorOverlayChange(() -> {
+ try {
+ mDevice.executeShellCommand("cmd overlay enable " + GESTURAL_OVERLAY_NAME);
+ } catch (IOException e) {
+ // Do nothing
}
- }
- mDevice.waitForIdle();
- leaveSettings();
-
- mDevice.pressHome();
- mDevice.waitForIdle();
-
- mDevice.waitForIdle();
+ });
}
- /**
- * Restore the original configured value for the system gesture by operating Settings.
- */
private void disableGestureNav() {
if (!hasSystemGestureFeature()) {
return;
}
-
- if (mRevertOverlay) {
+ monitorOverlayChange(() -> {
try {
- mDevice.executeShellCommand("cmd overlay disable " + GESTURAL_OVERLAY_NAME);
- } catch (IOException e) {
+ mDevice.executeShellCommand("cmd overlay enable " + mOriginalOverlayPackage);
+ } catch (IOException ignore) {
// Do nothing
}
- if (!isGestureMode()) {
- return;
- }
+ });
+ }
+
+ private void getCurrentInsetsSize(Rect outSize) {
+ outSize.setEmpty();
+ if (mWindowManager != null) {
+ WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+ Insets navInsets = insets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.navigationBars());
+ insetsToRect(navInsets, outSize);
}
+ }
- if (mConfiguredInSettings) {
- launchToSettingsSystemGesture();
- for (Map.Entry<String, Boolean> entry : mSystemGestureOptionsMap.entrySet()) {
- if (entry.getValue()) {
- UiObject2 navigationObject = findSystemNavigationObject(entry.getKey(), false);
- if (navigationObject != null) {
- navigationObject.click();
- }
+ // Monitoring the navigation bar insets size change as a hint of gesture mode has changed, not
+ // the best option for every kind of devices. We can consider listening OVERLAY_CHANGED
+ // broadcast in U.
+ private void monitorOverlayChange(Runnable overlayChangeCommand) {
+ if (mWindowManager != null) {
+ final Rect initSize = new Rect();
+ getCurrentInsetsSize(initSize);
+
+ overlayChangeCommand.run();
+ // wait for insets size change
+ final Rect peekSize = new Rect();
+ int t = 0;
+ while (t < WAIT_OVERLAY_TIMEOUT) {
+ SystemClock.sleep(PEEK_INTERVAL);
+ t += PEEK_INTERVAL;
+ getCurrentInsetsSize(peekSize);
+ if (!peekSize.equals(initSize)) {
+ break;
}
}
- leaveSettings();
+ } else {
+ // shouldn't happen
+ overlayChangeCommand.run();
+ SystemClock.sleep(WAIT_OVERLAY_TIMEOUT);
}
}
@@ -266,20 +200,23 @@ public class GestureNavRule extends ExternalResource {
assumeTrue("Gesture navigation required", isGestureMode);
}
- private boolean isGestureMode() {
- // TODO: b/153032202 consider the CTS on GSI case.
+ private int getCurrentNavMode() {
Resources res = mTargetContext.getResources();
int naviModeId = res.getIdentifier(NAV_BAR_INTERACTION_MODE_RES_NAME, "integer", "android");
- int naviMode = res.getInteger(naviModeId);
- return naviMode == NAV_BAR_INTERACTION_MODE_GESTURAL;
+ return res.getInteger(naviModeId);
}
- private static String getSettingsString(Resources res, String strResName) {
- int resIdString = res.getIdentifier(strResName, "string", SETTINGS_PACKAGE_NAME);
- if (resIdString <= MIN_APPLICATION_RES_ID) {
- return null;
- }
+ private boolean containsNavigationBar() {
+ final Rect peekSize = new Rect();
+ getCurrentInsetsSize(peekSize);
+ return peekSize.height() != 0;
+ }
- return res.getString(resIdString);
+ private boolean isGestureMode() {
+ if (!containsNavigationBar()) {
+ return false;
+ }
+ final int naviMode = getCurrentNavMode();
+ return naviMode == NAV_BAR_MODE_GESTURAL;
}
}
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index 24d1249d9cc..8884bf60c26 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -207,6 +207,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
"Landroid/os/IVoldListener;",
"Landroid/os/IVoldMountCallback;",
"Landroid/os/IVoldTaskListener;",
+ "Landroid/os/TouchOcclusionMode;",
"Landroid/os/storage/CrateMetadata;",
"Landroid/view/LayerMetadataKey;",
"Lcom/android/internal/annotations/CompositeRWLock;",
@@ -1056,6 +1057,8 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
.put("androidx.window.sidecar",
ImmutableSet.of("Landroidx/window/common/", "Landroidx/window/sidecar",
"Landroidx/window/util"))
+ .put("com.google.android.camera.experimental2019",
+ ImmutableSet.of("Landroidx/annotation"))
.put("com.google.android.camera.experimental2020_midyear",
ImmutableSet.of("Landroidx/annotation"))
.build();
@@ -1075,7 +1078,8 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
* and shared library jars.
*/
@Test
- public void testNoKotlinFilesInClasspaths() {
+ public void testNoKotlinFilesInClasspaths() throws Exception {
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
ImmutableList<String> kotlinFiles =
Stream.of(sBootclasspathJars.stream(),
sSystemserverclasspathJars.stream(),
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 4da5fff7f0b..9c8a81d05f7 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -25,6 +25,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import java.util.ArrayList;
/**
@@ -41,6 +43,7 @@ public class UserControlDisabledPackagesTest extends BaseDeviceOwnerTest {
private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
private static final String SIMPLE_APP_ACTIVITY =
"com.android.cts.launcherapps.simpleapp.SimpleActivityImmediateExit";
+ private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
public void testSetUserControlDisabledPackages() throws Exception {
ArrayList<String> protectedPackages = new ArrayList<>();
@@ -86,14 +89,15 @@ public class UserControlDisabledPackagesTest extends BaseDeviceOwnerTest {
// Check if package is part of UserControlDisabledPackages before checking if
// package is stopped since it is a necessary condition to prevent stopping of
// package
-
assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
.containsExactly(SIMPLE_APP_PKG);
- assertPackageRunningState(/* running= */ true);
+ assertPackageRunningState(/* running= */ true,
+ InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
}
public void testFgsStopWithUserControlEnabled() throws Exception {
- assertPackageRunningState(/* running= */ false);
+ assertPackageRunningState(/* running= */ false,
+ InstrumentationRegistry.getArguments().getString(ARG_PID_BEFORE_STOP, "-1"));
assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
}
@@ -120,9 +124,15 @@ public class UserControlDisabledPackagesTest extends BaseDeviceOwnerTest {
return pid.length() > 0;
}
- private void assertPackageRunningState(boolean shouldBeRunning) throws Exception {
+ private void assertPackageRunningState(boolean shouldBeRunning, String argPid)
+ throws Exception {
+ String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
+
+ final boolean samePid = pid.equals(argPid);
+ final boolean stillRunning = samePid && isPackageRunning(SIMPLE_APP_PKG);
+
assertWithMessage("Package %s running for user %s", SIMPLE_APP_PKG,
getCurrentUser().getIdentifier())
- .that(isPackageRunning(SIMPLE_APP_PKG)).isEqualTo(shouldBeRunning);
+ .that(stillRunning).isEqualTo(shouldBeRunning);
}
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index c87a7f8d7f4..d1773d0e8e6 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -70,6 +70,7 @@ public class DeviceOwnerTest extends BaseDeviceOwnerTest {
private static final String TEST_APP_LOCATION = "/data/local/tmp/cts/packageinstaller/";
private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
+ private static final String ARG_PID_BEFORE_STOP = "pidOfSimpleapp";
private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
"CtsHasLauncherActivityApp.apk";
@@ -1059,13 +1060,16 @@ public class DeviceOwnerTest extends BaseDeviceOwnerTest {
*/
private void tryFgsStoppingProtectedPackage(int userId, boolean canUserStopPackage)
throws Exception {
+ String pid = executeShellCommand(String.format("pidof %s", SIMPLE_APP_PKG)).trim();
fgsStopPackageForUser(SIMPLE_APP_PKG, userId);
if (canUserStopPackage) {
executeDeviceTestMethod(".UserControlDisabledPackagesTest",
- "testFgsStopWithUserControlEnabled");
+ "testFgsStopWithUserControlEnabled",
+ Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
} else {
executeDeviceTestMethod(".UserControlDisabledPackagesTest",
- "testFgsStopWithUserControlDisabled");
+ "testFgsStopWithUserControlDisabled",
+ Collections.singletonMap(ARG_PID_BEFORE_STOP, pid));
}
}
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 527e8ef842b..0e2a887bc40 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -91,7 +91,7 @@ android_test_helper_app {
// Tag as a CTS artifact
test_suites: [
"general-tests",
- "mts",
+ "mts-mediaprovider",
"cts",
],
}
@@ -155,7 +155,7 @@ android_test_helper_app {
// Tag as a CTS artifact
test_suites: [
"general-tests",
- "mts",
+ "mts-mediaprovider",
"cts",
],
}
@@ -171,7 +171,7 @@ android_test_helper_app {
// Tag as a CTS artifact
test_suites: [
"general-tests",
- "mts",
+ "mts-mediaprovider",
"cts",
],
}
@@ -187,7 +187,7 @@ android_test_helper_app {
// Tag as a CTS artifact
test_suites: [
"general-tests",
- "mts",
+ "mts-mediaprovider",
"cts",
],
}
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 35cb549c529..4df785c9a8d 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.queryAudioFile;
import static android.scopedstorage.cts.lib.TestUtils.queryFile;
import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending;
import static android.scopedstorage.cts.lib.TestUtils.queryImageFile;
@@ -3023,6 +3024,45 @@ public class ScopedStorageDeviceTest extends ScopedStorageBaseDeviceTest {
}
}
+ /**
+ * Test that renaming a file to {@link Environment#DIRECTORY_RINGTONES} sets
+ * {@link MediaStore.Audio.AudioColumns#IS_RINGTONE}
+ */
+
+ @Test
+ public void testRenameToRingtoneDirectory() throws Exception {
+ final File fileInDownloads = new File(getDownloadDir(), AUDIO_FILE_NAME);
+ final File fileInRingtones = new File(getRingtonesDir(), AUDIO_FILE_NAME);
+
+ try {
+ assertThat(fileInDownloads.createNewFile()).isTrue();
+ assertThat(MediaStore.scanFile(getContentResolver(), fileInDownloads)).isNotNull();
+
+ assertCanRenameFile(fileInDownloads, fileInRingtones);
+
+ try (Cursor c = queryAudioFile(fileInRingtones,
+ MediaStore.Audio.AudioColumns.IS_RINGTONE)) {
+ assertTrue(c.moveToFirst());
+ assertWithMessage("Expected " + MediaStore.Audio.AudioColumns.IS_RINGTONE
+ + " to be set after renaming to " + fileInRingtones)
+ .that(c.getInt(0)).isEqualTo(1);
+ }
+
+ assertCanRenameFile(fileInRingtones, fileInDownloads);
+
+ try (Cursor c = queryAudioFile(fileInDownloads,
+ MediaStore.Audio.AudioColumns.IS_RINGTONE)) {
+ assertTrue(c.moveToFirst());
+ assertWithMessage("Expected " + MediaStore.Audio.AudioColumns.IS_RINGTONE
+ + " to be unset after renaming to " + fileInDownloads)
+ .that(c.getInt(0)).isEqualTo(0);
+ }
+ } finally {
+ fileInDownloads.delete();
+ fileInRingtones.delete();
+ }
+ }
+
@Test
@SdkSuppress(minSdkVersion = 31, codeName = "S")
public void testTransformsDirFileOperations() throws Exception {
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 06706398258..2e694ed65a7 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -751,6 +751,17 @@ public class TestUtils {
}
/**
+ * Queries {@link ContentResolver} for an audio file and returns a {@link Cursor} with the given
+ * columns.
+ */
+ @NonNull
+ public static Cursor queryAudioFile(File file, String... projection) {
+ return queryFile(getContentResolver(),
+ MediaStore.Audio.Media.getContentUri(sStorageVolumeName), file,
+ /*includePending*/ true, projection);
+ }
+
+ /**
* Queries {@link ContentResolver} for a file and returns the corresponding mime type for its
* entry in the database.
*/
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 13ade8b0585..dea26887143 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -116,8 +116,6 @@ public class SELinuxHostTest extends BaseHostJUnit4Test {
private File devicePcFile;
private File deviceSvcFile;
private File seappNeverAllowFile;
- private File libsepolwrap;
- private File libcpp;
private File copyLibcpp;
private File sepolicyTests;
@@ -907,29 +905,8 @@ public class SELinuxHostTest extends BaseHostJUnit4Test {
return (os.startsWith("mac") || os.startsWith("darwin"));
}
- private void setupLibraries() throws Exception {
- // The host side binary tests are host OS specific. Use Linux
- // libraries on Linux and Mac libraries on Mac.
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
- if (isMac()) {
- libsepolwrap = buildHelper.getTestFile("libsepolwrap.dylib");
- libcpp = buildHelper.getTestFile("libc++.dylib");
- copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.dylib");
- Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
- } else {
- libsepolwrap = buildHelper.getTestFile("libsepolwrap.so");
- libcpp = buildHelper.getTestFile("libc++.so");
- copyLibcpp = new File(System.getProperty("java.io.tmpdir") + "/libc++.so");
- Files.copy(libcpp.toPath(), copyLibcpp.toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
- libsepolwrap.deleteOnExit();
- libcpp.deleteOnExit();
- copyLibcpp.deleteOnExit();
- }
-
private void assertSepolicyTests(String test, String testExecutable,
boolean includeVendorSepolicy) throws Exception {
- setupLibraries();
sepolicyTests = copyResourceToTempFile(testExecutable);
sepolicyTests.setExecutable(true);
@@ -951,12 +928,6 @@ public class SELinuxHostTest extends BaseHostJUnit4Test {
}
ProcessBuilder pb = new ProcessBuilder(args);
- Map<String, String> env = pb.environment();
- if (isMac()) {
- env.put("DYLD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
- } else {
- env.put("LD_LIBRARY_PATH", System.getProperty("java.io.tmpdir"));
- }
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
pb.redirectErrorStream(true);
Process p = pb.start();
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
new file mode 100644
index 00000000000..4755ddbb229
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39795 extends StsExtraBusinessLogicHostTestBase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_39795";
+ private static final String DIR_PATH = "/storage/emulated/0/Android/data/CVE-2021-39795-dir";
+
+ @AsbSecurityTest(cveBugId = 201667614)
+ @Test
+ public void testPocCVE_2021_39795() {
+ ITestDevice device = null;
+ try {
+ device = getDevice();
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39795.apk");
+
+ /* Make a directory inside "Android/data" folder */
+ AdbUtils.runCommandLine("mkdir " + DIR_PATH, device);
+
+ /* Allow Read and Write to external storage */
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.READ_EXTERNAL_STORAGE", device);
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.WRITE_EXTERNAL_STORAGE", device);
+
+ /* Allow the app to manage all files */
+ AdbUtils.runCommandLine(
+ "appops set --uid " + TEST_PKG + " MANAGE_EXTERNAL_STORAGE allow", device);
+
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DeviceTest", "testFilePresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ AdbUtils.runCommandLine("rm -rf " + DIR_PATH, device);
+ } catch (Exception e) {
+ // ignore the exceptions
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
index 7f819bcaab4..ef3e6cdf869 100644
--- a/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/BUG-182282630/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts.BUG_182282630"
android:targetSandboxVersion="2">
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:label="@string/app_name"
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
new file mode 100644
index 00000000000..ade2215f2d7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39795",
+ defaults: [
+ "cts_support_defaults"
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
new file mode 100644
index 00000000000..cb42aedc255
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39795">
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39795" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml
new file mode 100644
index 00000000000..19ea461d4cb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="filePath">Android/data/CVE-2021-39795-dir/</string>
+ <string name="fileContent">Bypassed by MediaProvider</string>
+ <string name="fileName">CVE-2021-39795-file</string>
+ <string name="external">external</string>
+ <string name="secondFixFailure">Second Fix Patch not applied.
+ Please Apply second Fix Patch!!</string>
+ <string name="fileUtilPkg">com.android.providers.media.util.FileUtils</string>
+ <string name="isDataOrObbPathMethod">isDataOrObbPath</string>
+ <string name="mediaProviderPkg">com.android.providers.media.module</string>
+ <string name="sampleFilePath">/storage/emulated/0/Android/data/foo</string>
+ <string name="failure">Device vulnerable to b/201667614! Any app with
+ MANAGE_EXTERNAL_STORAGE permission can write into other apps private
+ external directory.</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
new file mode 100644
index 00000000000..8d3ff0a9602
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39795/src/android/security/cts/CVE_2021_39795/DeviceTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39795;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.res.Resources;
+import android.provider.MediaStore;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testFilePresence() {
+ boolean isSecondPatchAbsent = false;
+ Resources resources = null;
+ OutputStream outputStream = null;
+ try {
+ // Accessing FileUtils.isDataOrObbPath() to detect the presence of second patch of fix.
+ Context context = getApplicationContext();
+ resources = context.getResources();
+ Context mediaProviderContext =
+ context.createPackageContext(resources.getString(R.string.mediaProviderPkg),
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ ClassLoader fileUtilsClassLoader = mediaProviderContext.getClassLoader();
+ Class<?> FileUtilsClass =
+ fileUtilsClassLoader.loadClass(resources.getString(R.string.fileUtilPkg));
+ Method isDataOrObbPathMethod = FileUtilsClass.getDeclaredMethod(
+ resources.getString(R.string.isDataOrObbPathMethod), String.class);
+ isDataOrObbPathMethod.setAccessible(true);
+ isSecondPatchAbsent = (boolean) isDataOrObbPathMethod.invoke(this,
+ resources.getString(R.string.sampleFilePath));
+
+ // Checking write into external directory.
+ ContentValues values = new ContentValues();
+ ContentResolver contentResolver = context.getContentResolver();
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH,
+ resources.getString(R.string.filePath));
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME,
+ resources.getString(R.string.fileName));
+ outputStream = contentResolver.openOutputStream(contentResolver.insert(
+ MediaStore.Files.getContentUri(resources.getString(R.string.external)),
+ values));
+ outputStream.write(resources.getString(R.string.fileContent).getBytes());
+
+ /*
+ * If control flow has reached till this point it means no exception anywhere and fix is
+ * not present and it is vulnerable to the bug.
+ */
+ fail(resources.getString(R.string.failure));
+ } catch (IllegalArgumentException e) {
+ // First fix patch is applied, ignore this exception.
+ if (isSecondPatchAbsent) {
+ // Fail the test as Latest Fix Patch is not applied
+ fail(resources.getString(R.string.secondFixFailure));
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ outputStream.close();
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
index 7b7e9e03a60..c7824bb2520 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
@@ -33,14 +33,17 @@ import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.photopicker.cts.util.GetContentActivityAliasUtils;
+import android.photopicker.cts.util.PhotoPickerUiUtils;
import android.util.Pair;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObjectNotFoundException;
+import androidx.test.uiautomator.UiScrollable;
import androidx.test.uiautomator.UiSelector;
import org.junit.After;
import org.junit.AfterClass;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -52,6 +55,9 @@ import java.util.List;
* exclusively.
*/
public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
+
+ public static final String TAG = "ActionGetContentOnlyTest";
+
private static String sDocumentsUiPackageName;
private static int sGetContentTakeOverActivityAliasState;
@@ -73,6 +79,12 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
public static void setUpBeforeClass() throws Exception {
sDocumentsUiPackageName = getDocumentsUiPackageName();
sGetContentTakeOverActivityAliasState = GetContentActivityAliasUtils.enableAndGetOldState();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
clearPackageData(sDocumentsUiPackageName);
}
@@ -82,6 +94,37 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
}
@Test
+ public void testMimeTypeFilter() throws Exception {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("audio/*");
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+ mDevice.waitForIdle();
+ // Should open documentsUi
+ assertThatShowsDocumentsUiButtons();
+
+ // We don't test the result of the picker here because the intention of the test is only to
+ // test that DocumentsUi is opened.
+ }
+
+ @Test
+ public void testExtraMimeTypeFilter() throws Exception {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("image/*");
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"video/*", "audio/*"});
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+ mDevice.waitForIdle();
+ // Should open documentsUi
+ assertThatShowsDocumentsUiButtons();
+
+ // We don't test the result of the picker here because the intention of the test is only to
+ // test that DocumentsUi is opened.
+ }
+
+ @Test
public void testBrowse_singleSelect() throws Exception {
final int itemCount = 1;
List<Pair<Uri, String>> createdImagesData = createImagesAndGetUriAndPath(itemCount,
@@ -135,6 +178,80 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
}
}
+ @Test
+ public void testChooserIntent_mediaFilter() throws Exception {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ mActivity.startActivityForResult(Intent.createChooser(intent, TAG), REQUEST_CODE);
+
+ // Should open Picker
+ assertThatShowsPickerUi();
+ }
+
+ @Test
+ public void testChooserIntent_nonMediaFilter() throws Exception {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("*/*");
+ mActivity.startActivityForResult(Intent.createChooser(intent, TAG), REQUEST_CODE);
+
+ // Should open DocumentsUi
+ assertThatShowsDocumentsUiButtons();
+ }
+
+ @Test
+ public void testPickerSupportedFromDocumentsUi() throws Exception {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("*/*");
+ mActivity.startActivityForResult(Intent.createChooser(intent, TAG), REQUEST_CODE);
+
+ findAndClickMediaIcon();
+
+ // Should open Picker
+ assertThatShowsPickerUi();
+ }
+
+ private void findAndClickMediaIcon() throws Exception {
+ final UiSelector appList = new UiSelector().resourceId(sDocumentsUiPackageName
+ + ":id/apps_row");
+
+ // Wait for the first app list item to appear
+ assertWithMessage("Waiting for app list to appear in DocumentsUi").that(
+ new UiObject(appList).waitForExists(SHORT_TIMEOUT)).isTrue();
+
+ String photoPickerAppName = "Media";
+ UiObject mediaButton = mDevice.findObject(new UiSelector().text(photoPickerAppName));
+
+ assertWithMessage("Timed out waiting for " + photoPickerAppName + " app icon to appear")
+ .that(new UiScrollable(appList).scrollIntoView(mediaButton)).isTrue();
+ mDevice.waitForIdle();
+
+ clickAndWait(mDevice, mediaButton);
+ }
+
+ private void assertThatShowsPickerUi() {
+ // Assert that Search bar for DocumentsUi shows
+ // Add a short timeout wait for DocumentsUi to show
+ assertThat(new UiObject(new UiSelector().resourceIdMatches(
+ PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/bottom_sheet"))
+ .waitForExists(SHORT_TIMEOUT)).isTrue();
+
+ // Assert that "Recent files" header for DocumentsUi shows
+ assertThat(new UiObject(new UiSelector().resourceIdMatches(
+ PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/privacy_text"))
+ .exists()).isTrue();
+
+ // Assert that Documents list UiObject for DocumentsUi shows
+ assertThat(new UiObject(new UiSelector().text("Photos")).exists()).isTrue();
+ assertThat(new UiObject(new UiSelector().text("Albums")).exists()).isTrue();
+ }
+
+ private void assertThatShowsDocumentsUiButtons() {
+ // Assert that "Recent files" header for DocumentsUi shows
+ // Add a short timeout wait for DocumentsUi to show
+ assertThat(new UiObject(new UiSelector().resourceId(sDocumentsUiPackageName
+ + ":id/header_title")).waitForExists(SHORT_TIMEOUT)).isTrue();
+ }
+
private UiObject findSaveButton() {
return new UiObject(new UiSelector().resourceId(
sDocumentsUiPackageName + ":id/container_save")
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
index bd173747fba..0f61dc74bbc 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
@@ -29,7 +29,10 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertThrows;
+
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
@@ -136,4 +139,21 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
assertPersistedGrant(uri, mContext.getContentResolver());
assertRedactedReadOnlyAccess(uri);
}
+
+ @Test
+ public void testMimeTypeFilter() throws Exception {
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+ intent.setType("audio/*");
+ assertThrows(ActivityNotFoundException.class,
+ () -> mActivity.startActivityForResult(intent, REQUEST_CODE));
+ }
+
+ @Test
+ public void testExtraMimeTypeFilter() throws Exception {
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"audio/*"});
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+ final GetResultActivity.Result res = mActivity.getResult();
+ assertThat(res.resultCode).isEqualTo(Activity.RESULT_CANCELED);
+ }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 3d0bcd3378f..440e47288c2 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -18,6 +18,7 @@ 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.PhotoPickerAssertionsUtils.assertContainsMimeType;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertMimeType;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPersistedGrant;
import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
@@ -578,6 +579,89 @@ 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 mp4VideoCount = 3;
+ // Creates 3 videos with mime type: "video/mp4"
+ mUriList.addAll(createVideosAndGetUris(mp4VideoCount, mContext.getUserId()));
+
+ final int imageCount = 4;
+ // Creates 4 images with mime type: "image/dng"
+ mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId()));
+
+ Intent intent = new Intent(mAction);
+ addMultipleSelectionFlag(intent);
+
+ if (Intent.ACTION_GET_CONTENT.equals(intent.getAction())) {
+ intent.setType("*/*");
+ }
+ final String[] mimeTypes = new String[]{"video/dng", "image/dng"};
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
+ launchPhotoPickerForIntent(intent);
+
+ final int totalCount = dngVideoCount + imageCount;
+ final List<UiObject> itemList = findItemList(totalCount);
+ final int itemCount = itemList.size();
+ assertThat(itemCount).isAtLeast(totalCount);
+ for (int i = 0; i < itemCount; i++) {
+ clickAndWait(mDevice, itemList.get(i));
+ }
+
+ clickAndWait(mDevice, findAddButton());
+
+ final ClipData clipData = mActivity.getResult().data.getClipData();
+ assertWithMessage("Expected number of items returned to be: " + itemCount)
+ .that(clipData.getItemCount()).isEqualTo(itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ final Uri uri = clipData.getItemAt(i).getUri();
+ assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
+ assertRedactedReadOnlyAccess(uri);
+ assertContainsMimeType(uri, mimeTypes);
+ }
+ }
+
+ @Test
+ public void testMimeTypeFilterPriority() throws Exception {
+ final int videoCount = 2;
+ mUriList.addAll(createDNGVideosAndGetUris(videoCount, mContext.getUserId()));
+ final int imageCount = 1;
+ mUriList.addAll(createImagesAndGetUris(imageCount, mContext.getUserId()));
+
+ Intent intent = new Intent(mAction);
+ addMultipleSelectionFlag(intent);
+ // setType has lower priority than EXTRA_MIME_TYPES filters.
+ intent.setType("image/*");
+ final String mimeType = "video/dng";
+ intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {mimeType});
+ launchPhotoPickerForIntent(intent);
+
+ // find all items
+ final List<UiObject> itemList = findItemList(-1);
+ final int itemCount = itemList.size();
+ assertThat(itemCount).isAtLeast(videoCount);
+ for (int i = 0; i < itemCount; i++) {
+ clickAndWait(mDevice, itemList.get(i));
+ }
+
+ clickAndWait(mDevice, findAddButton());
+
+ final ClipData clipData = mActivity.getResult().data.getClipData();
+ assertWithMessage("Expected number of items returned to be: " + itemCount)
+ .that(clipData.getItemCount()).isEqualTo(itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ final Uri uri = clipData.getItemAt(i).getUri();
+ assertPickerUriFormat(uri, mContext.getUserId());
+ assertPersistedGrant(uri, mContext.getContentResolver());
+ assertRedactedReadOnlyAccess(uri);
+ assertMimeType(uri, mimeType);
+ }
+ }
+
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/GetContentActivityAliasUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
index 493f6417f08..0ccdd3f280c 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/GetContentActivityAliasUtils.java
@@ -67,6 +67,11 @@ public class GetContentActivityAliasUtils {
public static void clearPackageData(String packageName) throws Exception {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand("pm clear " + packageName);
+
+ // We should ideally be listening to an effective measure to know if package data was
+ // cleared, like listening to a broadcasts or checking a value. But that information is
+ // very package private and not available.
+ Thread.sleep(500);
}
public static String getDocumentsUiPackageName() {
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
index d9749f27420..6d86cee66b9 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
@@ -80,6 +80,12 @@ public class PhotoPickerAssertionsUtils {
assertThat(resultMimeType).isEqualTo(expectedMimeType);
}
+ public static void assertContainsMimeType(Uri uri, String[] expectedMimeTypes) {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final String resultMimeType = context.getContentResolver().getType(uri);
+ assertThat(Arrays.asList(expectedMimeTypes).contains(resultMimeType)).isTrue();
+ }
+
public static void assertRedactedReadOnlyAccess(Uri uri) throws Exception {
assertThat(uri).isNotNull();
final String[] projection = new String[]{ PickerMediaColumns.MIME_TYPE };
diff --git a/tests/app/app/assets/picture_800_by_600.png b/tests/app/app/assets/picture_800_by_600.png
new file mode 100644
index 00000000000..dc8f3d49bdc
--- /dev/null
+++ b/tests/app/app/assets/picture_800_by_600.png
Binary files differ
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index 6db8aa69bed..bef1319fba1 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -32,6 +32,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.test.filters.SmallTest
+import com.android.compatibility.common.util.CddTest;
import com.google.common.truth.Truth.assertThat
import org.junit.Assume
import kotlin.test.assertFailsWith
@@ -283,8 +284,9 @@ class NotificationTemplateTest : NotificationTemplateTestBase() {
}
}
+ @CddTest(requirement = "3.8.3.1/C-2-1")
fun testPromoteBigPicture_withBigPictureUriIcon() {
- val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+ val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
val pictureIcon = Icon.createWithContentUri(pictureUri)
val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_media_play)
@@ -385,8 +387,9 @@ class NotificationTemplateTest : NotificationTemplateTestBase() {
!!.sameAs(picture)).isTrue()
}
+ @CddTest(requirement = "3.8.3.1/C-2-1")
fun testBigPicture_withBigLargeIcon_withContentUri() {
- val iconUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
+ val iconUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
val icon = Icon.createWithContentUri(iconUri)
val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_media_play)
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index d7dd63d1ff2..c9d03141af0 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -2925,7 +2925,18 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
* in CDD camera section 7.5
*/
@Test
- @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14")
+ @CddTest(requirements = {
+ "2.2.7.2/7.5/H-1-1",
+ "2.2.7.2/7.5/H-1-2",
+ "2.2.7.2/7.5/H-1-3",
+ "2.2.7.2/7.5/H-1-4",
+ "2.2.7.2/7.5/H-1-8",
+ "2.2.7.2/7.5/H-1-9",
+ "2.2.7.2/7.5/H-1-10",
+ "2.2.7.2/7.5/H-1-11",
+ "2.2.7.2/7.5/H-1-12",
+ "2.2.7.2/7.5/H-1-13",
+ "2.2.7.2/7.5/H-1-14"})
public void testCameraPerfClassCharacteristics() throws Exception {
if (mAdoptShellPerm) {
// Skip test for system camera. Performance class is only applicable for public camera
@@ -2956,7 +2967,8 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
PerformanceClassEvaluator.StreamUseCaseRequirement streamUseCaseReq =
pce.addR7_5__H_1_14();
- HashSet<String> primaryCameras = new HashSet<String>();
+ String primaryRearId = null;
+ String primaryFrontId = null;
for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
String cameraId = mCameraIdsUnderTest[i];
boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera(
@@ -2982,7 +2994,7 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
if (isPrimaryRear) {
- primaryCameras.add(cameraId);
+ primaryRearId = cameraId;
primaryRearReq.setPrimaryCameraSupported(true);
primaryRearReq.setResolution(sensorResolution);
hwLevelReq.setPrimaryRearCameraHwlLevel(staticInfo.getHardwareLevelChecked());
@@ -2997,6 +3009,8 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
long minFrameDuration = config.getOutputMinFrameDuration(
android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD);
primaryRearReq.setVideoFps(1e9 / minFrameDuration);
+ } else {
+ primaryRearReq.setVideoFps(-1);
}
// H-1-9
@@ -3023,7 +3037,7 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
}
hfrReq.setRear240FpsSupported(support240Fps);
} else {
- primaryCameras.add(cameraId);
+ primaryFrontId = cameraId;
primaryFrontReq.setPrimaryCameraSupported(true);
primaryFrontReq.setResolution(sensorResolution);
hwLevelReq.setPrimaryFrontCameraHwlLevel(staticInfo.getHardwareLevelChecked());
@@ -3036,6 +3050,8 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
long minFrameDuration = config.getOutputMinFrameDuration(
android.media.MediaRecorder.class, FULLHD);
primaryFrontReq.setVideoFps(1e9 / minFrameDuration);
+ } else {
+ primaryFrontReq.setVideoFps(-1);
}
}
@@ -3084,8 +3100,39 @@ public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase {
streamUseCaseReq.setFrontStreamUseCaseSupported(streamUseCaseSupported);
}
}
+
+ if (primaryRearId == null) {
+ primaryRearReq.setPrimaryCameraSupported(false);
+ primaryRearReq.setResolution(-1);
+ primaryRearReq.setVideoSizeReqSatisfied(false);
+ primaryRearReq.setVideoFps(-1);
+ hwLevelReq.setPrimaryRearCameraHwlLevel(-1);
+ timestampSourceReq.setRearCameraTimestampSource(
+ CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+ rearRawReq.setRearRawSupported(false);
+ hfrReq.setRear240FpsSupported(false);
+ ultrawideZoomRatioReq.setRearUltraWideZoomRatioReqMet(false);
+ previewStabilizationReq.setRearPreviewStabilizationSupported(false);
+ logicalMultiCameraReq.setRearLogicalMultiCameraReqMet(false);
+ streamUseCaseReq.setRearStreamUseCaseSupported(false);
+ }
+ if (primaryFrontId == null) {
+ primaryFrontReq.setPrimaryCameraSupported(false);
+ primaryFrontReq.setResolution(-1);
+ primaryFrontReq.setVideoSizeReqSatisfied(false);
+ primaryFrontReq.setVideoFps(-1);
+ hwLevelReq.setPrimaryFrontCameraHwlLevel(-1);
+ timestampSourceReq.setFrontCameraTimestampSource(
+ CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
+ ultrawideZoomRatioReq.setFrontUltraWideZoomRatioReqMet(false);
+ previewStabilizationReq.setFrontPreviewStabilizationSupported(false);
+ logicalMultiCameraReq.setFrontLogicalMultiCameraReqMet(false);
+ streamUseCaseReq.setFrontStreamUseCaseSupported(false);
+ }
+
// H-1-11
Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
+ Set<String> primaryCameras = new HashSet<>(Arrays.asList(primaryRearId, primaryFrontId));
boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras);
concurrentRearFrontReq.setConcurrentRearFrontSupported(supportPrimaryFrontBack);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
index 2c3934ccc75..bdf4bc6fde2 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CloneProfileDeviceOwnerTest.java
@@ -27,6 +27,7 @@ import android.os.UserManager;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -52,6 +53,7 @@ public class CloneProfileDeviceOwnerTest {
@EnsureHasDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@RequireRunOnPrimaryUser
+ @RequireMultiUserSupport
public void createCloneProfile_hasDeviceOwner_fails() {
assertThrows(NeneException.class,
() -> TestApis.users().createUser()
@@ -67,6 +69,7 @@ public class CloneProfileDeviceOwnerTest {
@EnsureHasNoDeviceOwner
@EnsureHasPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@RequireRunOnPrimaryUser
+ @RequireMultiUserSupport
public void createCloneProfile_noDeviceOwner_succeeds() {
UserReference cloneUser = TestApis.users().createUser()
.parent(TestApis.users().instrumented())
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 2688d11b415..9c2714c97d9 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertThrows;
import android.app.admin.RemoteDevicePolicyManager;
+import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.provider.Telephony;
@@ -65,6 +66,7 @@ public final class DefaultSmsApplicationTest {
private ComponentName mAdmin;
private RemoteDevicePolicyManager mDpm;
private TelephonyManager mTelephonyManager;
+ private RoleManager mRoleManager;
@Before
public void setUp() {
@@ -72,13 +74,15 @@ public final class DefaultSmsApplicationTest {
mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
+ mRoleManager = sContext.getSystemService(RoleManager.class);
}
// TODO(b/198588696): Add support is @RequireSmsCapable and @RequireNotSmsCapable
@Postsubmit(reason = "new test")
@PolicyAppliesTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_works() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -93,7 +97,8 @@ public final class DefaultSmsApplicationTest {
@Postsubmit(reason = "new test")
@PolicyDoesNotApplyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_unchanged() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
@@ -108,7 +113,8 @@ public final class DefaultSmsApplicationTest {
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_smsPackageDoesNotExist_unchanged() {
- assumeTrue(mTelephonyManager.isSmsCapable());
+ assumeTrue(mTelephonyManager.isSmsCapable()
+ || (mRoleManager != null && mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
mDpm.setDefaultSmsApplication(mAdmin, FAKE_SMS_APP_NAME);
@@ -135,7 +141,8 @@ public final class DefaultSmsApplicationTest {
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = DefaultSmsApplication.class)
public void setDefaultSmsApplication_notSmsCapable_unchanged() {
- assumeTrue(!mTelephonyManager.isSmsCapable());
+ assumeTrue(!mTelephonyManager.isSmsCapable()
+ && (mRoleManager == null || !mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)));
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
index eee4b10d821..1c35d480d81 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
@@ -54,6 +54,7 @@ import com.android.bedstead.harrier.annotations.EnsureHasNoWorkProfile;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.RequireFeature;
+import com.android.bedstead.harrier.annotations.RequireMultiUserSupport;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -174,6 +175,7 @@ public class DevicePolicyManagementRoleHolderTest {
@EnsureHasDeviceOwner
@RequireRunOnPrimaryUser
@EnsureHasNoSecondaryUser
+ @RequireMultiUserSupport
@Test
@CddTest(requirements = {"3.9.4/C-3-1"})
public void createAndManageUser_roleHolderIsInManagedUser() throws InterruptedException {
@@ -316,6 +318,7 @@ public class DevicePolicyManagementRoleHolderTest {
@EnsureHasNoWorkProfile
@RequireRunOnPrimaryUser
@EnsureHasNoDpc
+ @RequireMultiUserSupport
public void shouldAllowBypassingDevicePolicyManagementRoleQualification_withUsers_returnsFalse()
throws Exception {
resetInternalShouldAllowBypassingState();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
index b6c43f1b490..a26d3c2dbc9 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/BackNavigationLegacyGestureTest.java
@@ -23,10 +23,14 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
+import android.os.SystemClock;
import android.server.wm.TestJournalProvider.TestJournalContainer;
import android.server.wm.backlegacyapp.Components;
import android.support.test.uiautomator.UiDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.GestureNavRule;
@@ -74,7 +78,45 @@ public class BackNavigationLegacyGestureTest extends ActivityManagerTestBase {
private void doBackGesture() {
int midHeight = mUiDevice.getDisplayHeight() / 2;
int midWidth = mUiDevice.getDisplayWidth() / 2;
- mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+ quickSwipe(0, midHeight, midWidth, midHeight, 10);
mUiDevice.waitForIdle();
}
+
+ private void injectInputEventUnSynced(@NonNull InputEvent event) {
+ mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+ false /* waitForAnimations */);
+ }
+
+ /**
+ * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+ */
+ private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+ if (steps <= 0) {
+ steps = 1;
+ }
+ final long startDownTime = SystemClock.uptimeMillis();
+ MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+ MotionEvent.ACTION_DOWN, startX, startY, 0);
+ injectInputEventUnSynced(firstDown);
+
+ // inject in every 5 ms.
+ final int delayMillis = 5;
+ long nextEventTime = startDownTime + delayMillis;
+ final float stepGapX = (endX - startX) / steps;
+ final float stepGapY = (endY - startY) / steps;
+ for (int i = 0; i < steps; i++) {
+ SystemClock.sleep(delayMillis);
+ final float nextX = startX + stepGapX * i;
+ final float nextY = startY + stepGapY * i;
+ MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+ injectInputEventUnSynced(move);
+ nextEventTime += delayMillis;
+ }
+
+ SystemClock.sleep(delayMillis);
+ MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_UP, endX, endY, 0);
+ injectInputEventUnSynced(up);
+ }
}
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 08ddca145d9..2baa2f1d3be 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -33,10 +33,12 @@ import android.content.Intent;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.location.Geocoder;
import android.location.Geocoder.GeocodeListener;
+import android.platform.test.annotations.AppModeFull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.RetryRule;
import org.junit.Before;
@@ -73,6 +75,8 @@ public class GeocoderTest {
}
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation() {
assumeTrue(Geocoder.isPresent());
@@ -82,6 +86,8 @@ public class GeocoderTest {
verify(listener, timeout(10000)).onGeocode(anyList());
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation_sync() throws Exception {
assumeTrue(Geocoder.isPresent());
@@ -89,6 +95,8 @@ public class GeocoderTest {
mGeocoder.getFromLocation(60, 30, 5);
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocation")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocation_badInput() {
GeocodeListener listener = mock(GeocodeListener.class);
@@ -102,6 +110,8 @@ public class GeocoderTest {
() -> mGeocoder.getFromLocation(10, 181, 5, listener));
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName() {
assumeTrue(Geocoder.isPresent());
@@ -111,6 +121,8 @@ public class GeocoderTest {
verify(listener, timeout(10000)).onGeocode(anyList());
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName_sync() throws Exception {
assumeTrue(Geocoder.isPresent());
@@ -118,6 +130,8 @@ public class GeocoderTest {
mGeocoder.getFromLocationName("Dalvik,Iceland", 5);
}
+ @ApiTest(apis = "android.location.Geocoder#getFromLocationName")
+ @AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
public void testGetFromLocationName_badInput() {
GeocodeListener listener = mock(GeocodeListener.class);
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index 39b90fff698..143b795623c 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -27,6 +27,8 @@ import android.view.Display;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
+
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Ignore;
@@ -95,9 +97,16 @@ public class CodecInfoTest {
* default 10-bit profiles, those are excluded from this test.
*/
@Test
+ // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+ // display capabilities at native level, till then limit the test to vendor codecs
+ @NonMediaMainlineTest
+ @ApiTest(apis = "MediaCodecInfo.CodecCapabilities#profileLevels")
public void testHDRDisplayCapabilities() {
Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
+ // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
+ // display capabilities at native level, till then limit the test to vendor codecs
+ Assume.assumeTrue("Test is restricted to vendor codecs", isVendorCodec(mCodecName));
int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
@@ -161,7 +170,7 @@ public class CodecInfoTest {
// For devices launching with Android T, if a codec supports an HDR profile and device
// supports HDR display, it must advertise P010 support
int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
- if (FIRST_SDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
+ if (VNDK_IS_AT_LEAST_T && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
for (CodecProfileLevel pl : caps.profileLevels) {
if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 47662682d36..ef44528cbff 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -41,6 +41,7 @@ import android.media.MediaFormat;
import android.os.Build;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.SystemProperties;
import android.platform.test.annotations.LargeTest;
import android.platform.test.annotations.RequiresDevice;
import android.system.ErrnoException;
@@ -1012,6 +1013,9 @@ public class BitmapFactoryTest {
public void testDecode10BitHEIFTo10BitBitmap() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
BitmapFactory.Options opt = new BitmapFactory.Options();
@@ -1028,6 +1032,9 @@ public class BitmapFactoryTest {
public void testDecode10BitHEIFTo8BitBitmap() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
BitmapFactory.Options opt = new BitmapFactory.Options();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 6741c07ec21..b6689d87f54 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -49,6 +49,7 @@ import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.net.Uri;
import android.os.Build;
+import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.Size;
import android.util.TypedValue;
@@ -246,6 +247,9 @@ public class ImageDecoderTest {
public void testDecode10BitHeif() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
+ assumeTrue(
+ "Test needs VNDK at least T.",
+ SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
try {
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 6ac6d52dd8f..897e3df9d8e 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -103,6 +103,16 @@
android:label="FingerprintTestActivity">
</activity>
+ <receiver android:name="android.hardware.input.cts.tests.KeyboardLayoutChangeTest.CtsKeyboardLayoutProvider"
+ android:label="CTS keyboard layout provider"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
+ </intent-filter>
+ <meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS"
+ android:resource="@xml/keyboard_layouts" />
+ </receiver>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
new file mode 100644
index 00000000000..ca9040259d1
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_english_us.kcm
@@ -0,0 +1,311 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# English (US) keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_french.kcm b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
new file mode 100644
index 00000000000..65bcd132928
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_french.kcm
@@ -0,0 +1,336 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+ label: '\u00b2'
+ base: '\u00b2'
+}
+
+key 1 {
+ label: '1'
+ base: '&'
+ shift: '1'
+}
+
+key 2 {
+ label: '2'
+ base: '\u00e9'
+ shift: '2'
+ ralt: '~'
+}
+
+key 3 {
+ label: '3'
+ base: '"'
+ shift: '3'
+ ralt: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '\''
+ shift: '4'
+ ralt: '{'
+}
+
+key 5 {
+ label: '5'
+ base: '('
+ shift: '5'
+ ralt: '['
+}
+
+key 6 {
+ label: '6'
+ base: '-'
+ shift: '6'
+ ralt: '|'
+}
+
+key 7 {
+ label: '7'
+ base: '\u00e8'
+ shift: '7'
+ ralt: '`'
+}
+
+key 8 {
+ label: '8'
+ base: '_'
+ shift: '8'
+ ralt: '\\'
+}
+
+key 9 {
+ label: '9'
+ base: '\u00e7'
+ shift: '9'
+ ralt: '^'
+}
+
+key 0 {
+ label: '0'
+ base: '\u00e0'
+ shift: '0'
+ ralt: '@'
+}
+
+key MINUS {
+ label: ')'
+ base: ')'
+ shift: '\u00b0'
+ ralt: ']'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+ ralt: '}'
+}
+
+### ROW 2
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u02c6'
+ base: '\u0302'
+ shift: '\u0308'
+}
+
+key RIGHT_BRACKET {
+ label: '$'
+ base: '$'
+ shift: '\u00a3'
+ ralt: '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key APOSTROPHE {
+ label: '\u00f9'
+ base: '\u00f9'
+ shift: '%'
+}
+
+key BACKSLASH {
+ label: '*'
+ base: '*'
+ shift: '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '?'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: '.'
+}
+
+key PERIOD {
+ label: ':'
+ base: ':'
+ shift: '/'
+}
+
+key SLASH {
+ label: '!'
+ base: '!'
+ shift: '\u00a7'
+}
diff --git a/tests/tests/hardware/res/raw/keyboard_layout_german.kcm b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
new file mode 100644
index 00000000000..864af121245
--- /dev/null
+++ b/tests/tests/hardware/res/raw/keyboard_layout_german.kcm
@@ -0,0 +1,333 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# German keyboard layout, QWERTZ style.
+#
+
+type OVERLAY
+
+map key 12 SLASH # � ? \
+map key 21 Z
+map key 44 Y
+map key 53 MINUS # - _
+map key 86 PLUS # < > |
+
+### ROW 1
+
+key GRAVE {
+ label: '^'
+ base: '^'
+ shift: '\u00b0'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '\u00b2'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u00a7'
+ ralt: '\u00b3'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '&'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '/'
+ ralt: '{'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '('
+ ralt: '['
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: ')'
+ ralt: ']'
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: '='
+ ralt: '}'
+}
+
+key SLASH {
+ label: '\u00df'
+ base: '\u00df'
+ shift: '?'
+ ralt: '\\'
+}
+
+key EQUALS {
+ label: '\u00b4'
+ base: '\u0301'
+ shift: '\u0300'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+ ralt: '@'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key RIGHT_BRACKET {
+ label: '+'
+ base: '+'
+ shift: '*'
+ ralt: '~'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift, capslock: '\u00d6'
+}
+
+key APOSTROPHE {
+ label: '\u00c4'
+ base: '\u00e4'
+ shift, capslock: '\u00c4'
+}
+
+key BACKSLASH {
+ label: '#'
+ base: '#'
+ shift: '\''
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+ ralt: '|'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+ ralt: '\u00b5'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: ';'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: ':'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
diff --git a/tests/tests/hardware/res/xml/keyboard_layouts.xml b/tests/tests/hardware/res/xml/keyboard_layouts.xml
new file mode 100644
index 00000000000..4516a368bac
--- /dev/null
+++ b/tests/tests/hardware/res/xml/keyboard_layouts.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <keyboard-layout android:name="keyboard_layout_english_us"
+ android:label="English (US)"
+ android:keyboardLayout="@raw/keyboard_layout_english_us" />
+
+ <keyboard-layout android:name="keyboard_layout_german"
+ android:label="German"
+ android:keyboardLayout="@raw/keyboard_layout_german" />
+
+ <keyboard-layout android:name="keyboard_layout_french"
+ android:label="French"
+ android:keyboardLayout="@raw/keyboard_layout_french" />
+</keyboard-layouts>
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
index 7dae1d1e2ca..a12730ce7cf 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/KeyboardLayoutChangeTest.java
@@ -26,6 +26,9 @@ import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.timeout;
import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
import android.hardware.cts.R;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -36,6 +39,7 @@ import android.view.KeyEvent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Test;
@@ -44,6 +48,7 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@ApiTest(apis = {"android.view.InputDevice#getKeyCodeForKeyLocation"})
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KeyboardLayoutChangeTest extends InputHidTestCase {
@@ -201,4 +206,11 @@ public class KeyboardLayoutChangeTest extends InputHidTestCase {
timeout(KEYBOARD_LAYOUT_CHANGE_TIMEOUT)).onInputDeviceChanged(
eq(device.getId()));
}
+
+ public static class CtsKeyboardLayoutProvider extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Nothing to do at this time.
+ }
+ }
}
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
index 3bd9db68f5a..663ee1a80cd 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecResourceTest.java
@@ -308,8 +308,8 @@ public class MediaCodecResourceTest {
new IntentFilter(ACTION_LOW_PRIORITY_SERVICE_READY));
Intent intent = new Intent(context, MediaCodecResourceTestLowPriorityService.class);
context.startForegroundService(intent);
- // Starting the service and receiving the broadcast should take less than 1 second
- ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+ // Starting the service and receiving the broadcast should take less than 5 seconds
+ ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
context.unregisterReceiver(processInfoBroadcastReceiver);
return processInfo;
}
@@ -323,8 +323,8 @@ public class MediaCodecResourceTest {
Intent intent = new Intent(context, MediaCodecResourceTestHighPriorityActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
- // Starting the activity and receiving the broadcast should take less than 1 second
- ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(1000);
+ // Starting the activity and receiving the broadcast should take less than 5 seconds
+ ProcessInfo processInfo = processInfoBroadcastReceiver.waitForProcessInfoMs(5000);
context.unregisterReceiver(processInfoBroadcastReceiver);
return processInfo;
}
diff --git a/tests/tests/media/common/src/android/media/cts/CodecState.java b/tests/tests/media/common/src/android/media/cts/CodecState.java
index 3565fc85e2b..4aa9db47312 100644
--- a/tests/tests/media/common/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/common/src/android/media/cts/CodecState.java
@@ -169,13 +169,15 @@ public class CodecState {
}
}
- public void start() {
+ public void startCodec() {
mCodec.start();
mCodecInputBuffers = mCodec.getInputBuffers();
if (!mIsTunneled || mIsAudio) {
mCodecOutputBuffers = mCodec.getOutputBuffers();
}
+ }
+ public void play() {
if (mAudioTrack != null) {
mAudioTrack.play();
}
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 5e4df7f6c08..888cf235560 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -487,11 +487,13 @@ public class MediaCodecClearKeyPlayer implements MediaTimeProvider {
}
for (CodecState state : mVideoCodecStates.values()) {
- state.start();
+ state.startCodec();
+ state.play();
}
for (CodecState state : mAudioCodecStates.values()) {
- state.start();
+ state.startCodec();
+ state.play();
}
mDeltaTimeUs = -1;
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
index 0b495dd8fd9..879f561af6e 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecTunneledPlayer.java
@@ -44,11 +44,13 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
/** State the player starts in, before configuration. */
private static final int STATE_IDLE = 1;
/** State of the player during initial configuration. */
- private static final int STATE_PREPARING = 2;
+ private static final int STATE_PREPARED = 2;
+ /** State of the player after starting the codecs */
+ private static final int STATE_STARTED = 3;
/** State of the player during playback. */
- private static final int STATE_PLAYING = 3;
- /** State of the player when configured but not playing. */
- private static final int STATE_PAUSED = 4;
+ private static final int STATE_PLAYING = 4;
+ /** State of the player when playback is paused. */
+ private static final int STATE_PAUSED = 5;
private Boolean mThreadStarted = false;
private byte[] mSessionId;
@@ -194,7 +196,12 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
return true;
}
+ // Creates the extractors, identifies tracks and formats, and then calls MediaCodec.configure
public boolean prepare() throws IOException {
+ if (mState != STATE_IDLE) {
+ throw new IllegalStateException("Expected STATE_IDLE, got " + mState);
+ }
+
if (null == mAudioExtractor) {
mAudioExtractor = new MediaExtractor();
if (null == mAudioExtractor) {
@@ -237,9 +244,7 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
return false;
}
- synchronized (mState) {
- mState = STATE_PAUSED;
- }
+ mState = STATE_PREPARED;
return true;
}
@@ -306,70 +311,56 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
return format.containsKey(key) ? format.getInteger(key) : 0;
}
- public boolean start() {
+ // Calls MediaCodec.start
+ public void startCodec() {
Log.d(TAG, "start");
- synchronized (mState) {
- if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
- return true;
- } else if (mState == STATE_IDLE) {
- mState = STATE_PREPARING;
- return true;
- } else if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
-
- for (CodecState state : mVideoCodecStates.values()) {
- state.start();
- }
+ if (mState != STATE_PREPARED) {
+ throw new IllegalStateException("Expected STATE_PREAPRED, got " + mState);
+ }
- for (CodecState state : mAudioCodecStates.values()) {
- state.start();
- }
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.startCodec();
+ }
- mDeltaTimeUs = -1;
- mState = STATE_PLAYING;
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.startCodec();
}
- return false;
+
+ mDeltaTimeUs = -1;
+ mState = STATE_STARTED;
}
- public void startWork() throws IOException, Exception {
- try {
- // Just change state from STATE_IDLE to STATE_PREPARING.
- start();
- // Extract media information from uri asset, and change state to STATE_PAUSED.
- prepare();
- // Start CodecState, and change from STATE_PAUSED to STATE_PLAYING.
- start();
- } catch (IOException e) {
- throw e;
+ // Starts the decoding threads and then starts AudioTrack playback
+ public void play() {
+ if (mState != STATE_STARTED) {
+ throw new IllegalStateException("Expected STATE_STARTED, got " + mState);
}
+ mState = STATE_PLAYING;
synchronized (mThreadStarted) {
mThreadStarted = true;
mThread.start();
}
- }
- public void startThread() {
- start();
- synchronized (mThreadStarted) {
- mThreadStarted = true;
- mThread.start();
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.play();
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.play();
}
}
- // Pauses the audio track
+ // Pauses playback by pausing the AudioTrack
public void pause() {
Log.d(TAG, "pause");
- synchronized (mState) {
- if (mState == STATE_PAUSED) {
- return;
- } else if (mState != STATE_PLAYING) {
- throw new IllegalStateException();
- }
+ if (mState != STATE_PLAYING) {
+ throw new IllegalStateException("Expected STATE_PLAYING, got " + mState);
+ }
+ synchronized (mState) {
for (CodecState state : mVideoCodecStates.values()) {
state.pause();
}
@@ -382,43 +373,60 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
}
}
- public void flush() {
- Log.d(TAG, "flush");
+ // Resume playback when paused
+ public void resume() {
+ Log.d(TAG, "resume");
+
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
synchronized (mState) {
- if (mState == STATE_PLAYING || mState == STATE_PREPARING) {
- return;
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.play();
}
for (CodecState state : mAudioCodecStates.values()) {
- state.flush();
+ state.play();
}
- for (CodecState state : mVideoCodecStates.values()) {
- state.flush();
- }
+ mState = STATE_PLAYING;
}
}
- /** Seek all tracks to their very beginning.
+ public void flush() {
+ Log.d(TAG, "flush");
+
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.flush();
+ }
+
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.flush();
+ }
+ }
+
+ /** Seek all tracks to the first sample time.
*
* @param presentationTimeOffsetUs The offset for the presentation time to start at.
* @throws IllegalStateException if the player is not paused
*/
public void seekToBeginning(long presentationTimeOffsetUs) {
Log.d(TAG, "seekToBeginning");
- synchronized (mState) {
- if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
+ if (mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
+ }
- for (CodecState state : mVideoCodecStates.values()) {
- state.seekToBeginning(presentationTimeOffsetUs);
- }
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.seekToBeginning(presentationTimeOffsetUs);
+ }
- for (CodecState state : mAudioCodecStates.values()) {
- state.seekToBeginning(presentationTimeOffsetUs);
- }
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.seekToBeginning(presentationTimeOffsetUs);
}
}
@@ -426,53 +434,50 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
* Enables or disables looping. Should be called after {@link #prepare()}.
*/
public void setLoopEnabled(boolean enabled) {
- synchronized (mState) {
- if (mVideoCodecStates != null) {
- for (CodecState state : mVideoCodecStates.values()) {
- state.setLoopEnabled(enabled);
- }
- }
+ if (mState != STATE_PREPARED) {
+ throw new IllegalStateException("Expected STATE_PREPARED, got " + mState);
+ }
- if (mAudioCodecStates != null) {
- for (CodecState state : mAudioCodecStates.values()) {
- state.setLoopEnabled(enabled);
- }
- }
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.setLoopEnabled(enabled);
+ }
+
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.setLoopEnabled(enabled);
}
}
public void reset() {
- synchronized (mState) {
- if (mState == STATE_PLAYING) {
- pause();
- }
- if (mVideoCodecStates != null) {
- for (CodecState state : mVideoCodecStates.values()) {
- state.release();
- }
- mVideoCodecStates = null;
- }
-
- if (mAudioCodecStates != null) {
- for (CodecState state : mAudioCodecStates.values()) {
- state.release();
- }
- mAudioCodecStates = null;
+ if (mState == STATE_PLAYING) {
+ pause();
+ }
+ if (mVideoCodecStates != null) {
+ for (CodecState state : mVideoCodecStates.values()) {
+ state.release();
}
+ mVideoCodecStates = null;
+ }
- if (mAudioExtractor != null) {
- mAudioExtractor.release();
- mAudioExtractor = null;
+ if (mAudioCodecStates != null) {
+ for (CodecState state : mAudioCodecStates.values()) {
+ state.release();
}
+ mAudioCodecStates = null;
+ }
- if (mVideoExtractor != null) {
- mVideoExtractor.release();
- mVideoExtractor = null;
- }
+ if (mAudioExtractor != null) {
+ mAudioExtractor.release();
+ mAudioExtractor = null;
+ }
- mDurationUs = -1;
- mState = STATE_IDLE;
+ if (mVideoExtractor != null) {
+ mVideoExtractor.release();
+ mVideoExtractor = null;
}
+
+ mDurationUs = -1;
+ mState = STATE_IDLE;
+
synchronized (mThreadStarted) {
mThreadStarted = false;
}
@@ -607,6 +612,14 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
return mVideoCodecStates.get(0).getVideoTimeUs();
}
+ public long getVideoSystemTimeNs() {
+ if (mVideoCodecStates == null || mVideoCodecStates.get(0) == null) {
+ return -1;
+ }
+ return mVideoCodecStates.get(0).getVideoTimeUs();
+
+ }
+
/**
* Returns the ordered list of video frame timestamps rendered in tunnel mode.
*
@@ -643,39 +656,23 @@ public class MediaCodecTunneledPlayer implements MediaTimeProvider {
public Long queueOneVideoFrame() {
Log.d(TAG, "queueOneVideoFrame");
- if (mVideoCodecStates == null || !(mState == STATE_PLAYING || mState == STATE_PAUSED)) {
- return null;
+ if (mState != STATE_STARTED && mState != STATE_PAUSED) {
+ throw new IllegalStateException("Expected STARTED or PAUSED, got " + mState);
}
Long result = null;
- for (CodecState state : mVideoCodecStates.values()) {
- Long timestamp = state.doSomeWork(true /* mustWait */);
- if (timestamp != null) {
- result = timestamp;
+ if (mVideoCodecStates != null) {
+ for (CodecState state : mVideoCodecStates.values()) {
+ Long timestamp = state.doSomeWork(true /* mustWait */);
+ if (timestamp != null) {
+ result = timestamp;
+ }
}
}
return result;
}
/**
- * Resume playback when paused.
- *
- * @throws IllegalStateException if playback is not paused or if there is no configured audio
- * track.
- */
- public void resume() {
- Log.d(TAG, "resume");
- if (mAudioTrackState == null) {
- throw new IllegalStateException("Resuming playback with no audio track");
- }
- if (mState != STATE_PAUSED) {
- throw new IllegalStateException("Expected STATE_PAUSED, got " + mState);
- }
- mAudioTrackState.playAudioTrack();
- mState = STATE_PLAYING;
- }
-
- /**
* Configure video peek for the video codecs attached to the player.
*/
public void setVideoPeek(boolean enable) {
diff --git a/tests/tests/media/common/src/android/media/cts/TestUtils.java b/tests/tests/media/common/src/android/media/cts/TestUtils.java
index f98b3abf936..20bf143ca96 100644
--- a/tests/tests/media/common/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/common/src/android/media/cts/TestUtils.java
@@ -190,6 +190,7 @@ public final class TestUtils {
if (name.startsWith("c2.android.")) {
return true;
}
+ Log.d(TAG, "Test mode MTS does not test codec " + name);
return false;
}
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 145cfaf96fd..c9823760671 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecodeAccuracyTest.java
@@ -25,7 +25,6 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.MediaFormat;
-import android.media.cts.MediaCodecTunneledPlayer;
import android.media.cts.MediaHeavyPresubmitTest;
import android.media.cts.TestArgs;
import android.os.Environment;
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
index 0b8c50598b1..9926f04378f 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java
@@ -73,6 +73,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.DynamicConfigDeviceSide;
@@ -141,8 +142,6 @@ public class DecoderTest extends MediaTestBase {
private DisplayManager mDisplayManager;
static final Map<String, String> sDefaultDecoders = new HashMap<>();
- private static boolean mIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
-
protected static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
throws FileNotFoundException {
File inpFile = new File(mInpPrefix + res);
@@ -3884,11 +3883,10 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -3921,8 +3919,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback mode with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackHevc() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -3931,8 +3929,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback mode with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackAvc() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -3941,8 +3939,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback mode with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoPlaybackVp9() throws Exception {
tunneledVideoPlayback(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -3966,11 +3964,10 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -3990,8 +3987,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback flush with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushHevc() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4000,8 +3997,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback flush with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushAvc() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4010,23 +4007,19 @@ public class DecoderTest extends MediaTestBase {
/**
* Test tunneled video playback flush with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledVideoFlushVp9() throws Exception {
testTunneledVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
/**
- * Test tunneled video peek renders the first frame when on
+ * Test that the first frame is rendered when video peek is on in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
private void testTunneledVideoPeekOn(String mimeType, String videoName) throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOn requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4040,9 +4033,8 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
- mMediaCodecPlayer.start();
+ mMediaCodecPlayer.startCodec();
mMediaCodecPlayer.setVideoPeek(true); // Enable video peek
// Assert that onFirstTunnelFrameReady is called
@@ -4061,30 +4053,30 @@ public class DecoderTest extends MediaTestBase {
}
/**
- * Test tunneled video peek with HEVC renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnHevc() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled video peek with AVC renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnAvc() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled video peek with VP9 renders the first frame when on
+ * Test that the first frame is rendered when video peek is on for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOnVp9() throws Exception {
testTunneledVideoPeekOn(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
@@ -4092,15 +4084,11 @@ public class DecoderTest extends MediaTestBase {
/**
- * Test tunneled video peek doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
private void testTunneledVideoPeekOff(String mimeType, String videoName) throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledVideoPeekOff requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4114,9 +4102,8 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
- mMediaCodecPlayer.start();
+ mMediaCodecPlayer.startCodec();
mMediaCodecPlayer.setVideoPeek(false); // Disable video peek
// Assert that onFirstTunnelFrameReady is called
@@ -4142,75 +4129,40 @@ public class DecoderTest extends MediaTestBase {
}
/**
- * Test tunneled video peek with HEVC doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for HEC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffHevc() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled video peek with AVC doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffAvc() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled video peek with VP9 doesn't render the first frame when off and then turned on
+ * Test that peek off doesn't render the first frame until turned on for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodec#PARAMETER_KEY_TUNNEL_PEEK"})
public void testTunneledVideoPeekOffVp9() throws Exception {
testTunneledVideoPeekOff(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
- /**
- * Test tunneled audio PTS gaps with HEVC if supported.
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsHevc() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
- }
-
- /**
- * Test tunneled audio PTS gaps with AVC if supported
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsAvc() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- }
-
- /**
- * Test tunneled audio PTS gaps with VP9 if supported
- * If there exist PTS Gaps in AudioTrack playback, the framePosition returned by
- * AudioTrack#getTimestamp must not advance for any silent frames rendered to fill the
- * gap.
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioPtsGapsVp9() throws Exception {
- testTunneledAudioPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
- }
-
- private void testTunneledAudioPtsGaps(String mimeType, String fileName) throws Exception {
+ /**
+ * Test that audio timestamps don't progress during audio PTS gaps in tunneled mode.
+ */
+ private void testTunneledAudioProgressWithPtsGaps(String mimeType, String fileName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4224,11 +4176,10 @@ public class DecoderTest extends MediaTestBase {
final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4291,37 +4242,40 @@ public class DecoderTest extends MediaTestBase {
}
/**
- * Test tunneled audioTimestamp progress with underrun, with HEVC if supported
+ * Test that audio timestamps don't progress during audio PTS gaps for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunHevc() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsHevc() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled audioTimestamp progress with underrun, with AVC if supported.
+ * Test that audio timestamps don't progress during audio PTS gaps for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunAvc() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsAvc() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled audioTimestamp progress with underrun, with VP9 if supported.
+ * Test that audio timestamps don't progress during audio PTS gaps for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
- public void testTunneledAudioTimestampProgressWithUnderrunVp9() throws Exception {
- testTunneledAudioTimestampProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPtsGapsVp9() throws Exception {
+ testTunneledAudioProgressWithPtsGaps(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
- private void testTunneledAudioTimestampProgressWithUnderrun(
- String mimeType, String fileName) throws Exception {
+ /**
+ * Test that audio timestamps stop progressing during underrun in tunneled mode.
+ */
+ private void testTunneledAudioProgressWithUnderrun(String mimeType, String fileName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4335,11 +4289,10 @@ public class DecoderTest extends MediaTestBase {
final Uri mediaUri = Uri.fromFile(new File(mInpPrefix, fileName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4380,9 +4333,39 @@ public class DecoderTest extends MediaTestBase {
}
/**
- * Test accurate video rendering after a video MediaCodec flush.
+ * Test that audio timestamps stop progressing during underrun for HEVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunHevc() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during underrun for AVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunAvc() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during underrun for VP9 in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithUnderrunVp9() throws Exception {
+ testTunneledAudioProgressWithUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+ }
+
+ /**
+ * Test accurate video rendering after a flush in tunneled mode.
*
- * On some devices, queuing content when the player is paused, then triggering a flush, then
+ * Test On some devices, queuing content when the player is paused, then triggering a flush, then
* queuing more content does not behave as expected. The queued content gets lost and the flush
* is really only applied once playback has resumed.
*
@@ -4390,10 +4373,6 @@ public class DecoderTest extends MediaTestBase {
*/
private void testTunneledAccurateVideoFlush(String mimeType, String videoName)
throws Exception {
- if (!MediaUtils.check(mIsAtLeastS, "testTunneledAccurateVideoFlush requires Android 12")) {
- return;
- }
-
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4414,15 +4393,14 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
// Video peek might interfere with the test: we want to ensure that queuing more data during
// a pause does not cause displaying more video frames, which is precisely what video peek
// does.
mMediaCodecPlayer.setVideoPeek(false);
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4434,22 +4412,72 @@ public class DecoderTest extends MediaTestBase {
assertNotEquals("Audio timestamp has a zero frame position",
mMediaCodecPlayer.getTimestamp().framePosition, 0);
+ // Allow some time for playback to commence
+ Thread.sleep(500);
+
// Pause playback
mMediaCodecPlayer.pause();
- // Allow some time for playback to pause
- Thread.sleep(maxDrainTimeMs);
-
- // Verify that playback has paused
- long pauseAudioFramePositionUs = mMediaCodecPlayer.getTimestamp().framePosition;
- long pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
- Thread.sleep(maxDrainTimeMs);
- assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioFramePositionUs);
+
+ // Wait for audio to pause
+ AudioTimestamp pauseAudioTimestamp;
+ {
+ AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ // If it takes longer to pause, the UX won't feel responsive to the user
+ int audioPauseTimeoutMs = 250;
+ assertTrue(String.format("No audio pause after %d milliseconds",
+ audioPauseTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < audioPauseTimeoutMs);
+ pauseAudioTimestamp = currentAudioTimestamp;
+ Thread.sleep(50);
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (currentAudioTimestamp.framePosition != pauseAudioTimestamp.framePosition);
+ }
+ long pauseAudioSystemTimeMs = pauseAudioTimestamp.nanoTime / 1000 / 1000;
+
+ // Wait for video to pause
+ long pauseVideoSystemTimeNs;
+ long pauseVideoPositionUs;
+ {
+ long currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoUnderrunTimeoutMs = 2000;
+ assertTrue(String.format("No video pause after %d milliseconds",
+ videoUnderrunTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
+ pauseVideoSystemTimeNs = currentVideoSystemTimeNs;
+ Thread.sleep(250); // onFrameRendered can get delayed in the Framework
+ currentVideoSystemTimeNs = mMediaCodecPlayer.getCurrentRenderedSystemTimeNano();
+ } while (currentVideoSystemTimeNs != pauseVideoSystemTimeNs);
+ pauseVideoPositionUs = mMediaCodecPlayer.getVideoTimeUs();
+ }
+ long pauseVideoSystemTimeMs = pauseVideoSystemTimeNs / 1000 / 1000;
+
+ // Video should not continue running for a long period of time after audio pauses
+ long pauseVideoToleranceMs = 500;
+ assertTrue(String.format(
+ "Video ran %d milliseconds longer than audio (video:%d audio:%d)",
+ pauseVideoToleranceMs, pauseVideoSystemTimeMs, pauseAudioSystemTimeMs),
+ pauseVideoSystemTimeMs - pauseAudioSystemTimeMs < pauseVideoToleranceMs);
+
+ // Verify that playback stays paused
+ Thread.sleep(500);
+ assertEquals(mMediaCodecPlayer.getTimestamp().framePosition, pauseAudioTimestamp.framePosition);
+ assertEquals(mMediaCodecPlayer.getCurrentRenderedSystemTimeNano(), pauseVideoSystemTimeNs);
assertEquals(mMediaCodecPlayer.getVideoTimeUs(), pauseVideoPositionUs);
- // Verify audio and video are in sync
- assertTrue(String.format("Video pts (%d) is ahead of audio pts (%d)",
- pauseVideoPositionUs, pauseAudioFramePositionUs),
- pauseVideoPositionUs <= pauseAudioFramePositionUs);
+ // Verify audio and video are roughly in sync when paused
+ long framePosition = mMediaCodecPlayer.getTimestamp().framePosition;
+ long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
+ long pauseAudioPositionMs = pauseAudioTimestamp.framePosition * 1000 / playbackRateFps;
+ long pauseVideoPositionMs = pauseVideoPositionUs / 1000;
+ long deltaMs = pauseVideoPositionMs - pauseAudioPositionMs;
+ assertTrue(String.format(
+ "Video is %d milliseconds out of sync from audio (video:%d audio:%d)",
+ deltaMs, pauseVideoPositionMs, pauseAudioPositionMs),
+ deltaMs > -80 && deltaMs < pauseVideoToleranceMs);
// Flush both audio and video pipelines
mMediaCodecPlayer.flush();
@@ -4493,8 +4521,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test accurate video rendering after a video MediaCodec flush with HEVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushHevc() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_HEVC,
"video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
@@ -4503,8 +4531,8 @@ public class DecoderTest extends MediaTestBase {
/**
* Test accurate video rendering after a video MediaCodec flush with AVC if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushAvc() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_AVC,
"video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
@@ -4513,49 +4541,18 @@ public class DecoderTest extends MediaTestBase {
/**
* Test accurate video rendering after a video MediaCodec flush with VP9 if supported
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAccurateVideoFlushVp9() throws Exception {
testTunneledAccurateVideoFlush(MediaFormat.MIMETYPE_VIDEO_VP9,
"bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
/**
- * Test tunneled audioTimestamp progress with HEVC if supported
+ * Test that audio timestamps stop progressing during pause in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressHevc() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
- }
-
- /**
- * Test tunneled audioTimestamp progress with AVC if supported
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressAvc() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- }
-
- /**
- * Test tunneled audioTimestamp progress with VP9 if supported
- */
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
- @Test
- public void testTunneledAudioTimestampProgressVp9() throws Exception {
- testTunneledAudioTimestampProgress(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
- }
-
- /**
- * Test that AudioTrack timestamps don't advance after pause.
- */
- private void
- testTunneledAudioTimestampProgress(String mimeType, String videoName) throws Exception
- {
+ private void testTunneledAudioProgressWithPause(String mimeType, String videoName)
+ throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
return;
@@ -4568,11 +4565,10 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4604,14 +4600,43 @@ public class DecoderTest extends MediaTestBase {
assertEquals(audioTimestampAfterPause.nanoTime, mMediaCodecPlayer.getTimestamp().nanoTime);
}
+
/**
- * Test tunneled audio underrun, if supported.
- *
- * Underrun test with lower pts after underrun.
+ * Test that audio timestamps stop progressing during pause for HEVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseHevc() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during pause for AVC in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseAvc() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_AVC,
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
+ }
+
+ /**
+ * Test that audio timestamps stop progressing during pause for VP9 in tunneled mode.
+ */
+ @Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
+ public void testTunneledAudioProgressWithPauseVp9() throws Exception {
+ testTunneledAudioProgressWithPause(MediaFormat.MIMETYPE_VIDEO_VP9,
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
+ }
+
+ /**
+ * Test that audio underrun pauses video and resumes in-sync in tunneled mode.
*
* TODO(b/182915887): Test all the codecs advertised by the DUT for the provided test content
*/
- private void tunneledAudioUnderrun(String mimeType, String videoName, int frameRate)
+ private void tunneledAudioUnderrun(String mimeType, String videoName)
throws Exception {
if (!MediaUtils.check(isVideoFeatureSupported(mimeType, FEATURE_TunneledPlayback),
"No tunneled video playback codec found for MIME " + mimeType)) {
@@ -4625,11 +4650,10 @@ public class DecoderTest extends MediaTestBase {
Uri mediaUri = Uri.fromFile(new File(mInpPrefix, videoName));
mMediaCodecPlayer.setAudioDataSource(mediaUri, null);
mMediaCodecPlayer.setVideoDataSource(mediaUri, null);
- assertTrue("MediaCodecPlayer.start() failed!", mMediaCodecPlayer.start());
assertTrue("MediaCodecPlayer.prepare() failed!", mMediaCodecPlayer.prepare());
+ mMediaCodecPlayer.startCodec();
- // Starts video playback
- mMediaCodecPlayer.startThread();
+ mMediaCodecPlayer.play();
sleepUntil(() ->
mMediaCodecPlayer.getCurrentPosition() > CodecState.UNINITIALIZED_TIMESTAMP
&& mMediaCodecPlayer.getTimestamp() != null
@@ -4645,36 +4669,39 @@ public class DecoderTest extends MediaTestBase {
mMediaCodecPlayer.simulateAudioUnderrun(true);
// Wait for audio underrun
- final int audioUnderrunTimeoutMs = 1000; // Arbitrary upper time limit on loop time duration
- long startTimeMs = System.currentTimeMillis();
- AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
AudioTimestamp underrunAudioTimestamp;
- do {
- assertTrue(String.format("No audio underrun after %d milliseconds",
- System.currentTimeMillis() - startTimeMs),
- System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
- underrunAudioTimestamp = currentAudioTimestamp;
- Thread.sleep(50);
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
- } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
-
+ {
+ AudioTimestamp currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int audioUnderrunTimeoutMs = 1000;
+ assertTrue(String.format("No audio underrun after %d milliseconds",
+ System.currentTimeMillis() - startTimeMs),
+ System.currentTimeMillis() - startTimeMs < audioUnderrunTimeoutMs);
+ underrunAudioTimestamp = currentAudioTimestamp;
+ Thread.sleep(50);
+ currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (currentAudioTimestamp.framePosition != underrunAudioTimestamp.framePosition);
+ }
- // Wait until video playback stalls
- final int videoUnderrunTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- long underrunVideoTimeUs = -1;
- do {
- assertTrue(String.format("No video underrun after %d milliseconds",
- videoUnderrunTimeoutMs),
- System.currentTimeMillis() - startTimeMs < videoUnderrunTimeoutMs);
- underrunVideoTimeUs = currentVideoTimeUs;
- Thread.sleep(50);
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- } while (currentVideoTimeUs != underrunVideoTimeUs);
+ // Wait until video playback pauses due to underrunning audio
+ long pausedVideoTimeUs = -1;
+ {
+ long currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoPauseTimeoutMs = 2000;
+ assertTrue(String.format("No video pause after %d milliseconds",
+ videoPauseTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoPauseTimeoutMs);
+ pausedVideoTimeUs = currentVideoTimeUs;
+ Thread.sleep(250); // onFrameRendered messages can get delayed in the Framework
+ currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (currentVideoTimeUs != pausedVideoTimeUs);
+ }
- // Retrieve index for the video rendered frame at the time of underrun
- int underrunVideoRenderedTimestampIndex =
+ // Retrieve index for the video rendered frame at the time of video pausing
+ int pausedVideoRenderedTimestampIndex =
mMediaCodecPlayer.getRenderedVideoFrameTimestampList().size() - 1;
// Resume audio buffering with a negative offset, in order to simulate a desynchronisation.
@@ -4683,35 +4710,38 @@ public class DecoderTest extends MediaTestBase {
mMediaCodecPlayer.simulateAudioUnderrun(false);
// Wait until audio playback resumes
- final int audioResumeTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
AudioTimestamp postResumeAudioTimestamp;
- do {
- assertTrue(String.format("Audio has not resumed after %d milliseconds",
- audioResumeTimeoutMs),
- System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
- postResumeAudioTimestamp = currentAudioTimestamp;
- Thread.sleep(50);
- currentAudioTimestamp = mMediaCodecPlayer.getTimestamp();
- } while(currentAudioTimestamp.framePosition == postResumeAudioTimestamp.framePosition);
+ {
+ AudioTimestamp previousAudioTimestamp;
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int audioResumeTimeoutMs = 1000;
+ assertTrue(String.format("Audio has not resumed after %d milliseconds",
+ audioResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < audioResumeTimeoutMs);
+ previousAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ Thread.sleep(50);
+ postResumeAudioTimestamp = mMediaCodecPlayer.getTimestamp();
+ } while (postResumeAudioTimestamp.framePosition == previousAudioTimestamp.framePosition);
+ }
// Now that audio playback has resumed, wait until video playback resumes
- // We care about the timestamp of the first output frame, rather than the exact time the
- // video resumed, which is why we only start polling after we are sure audio playback has
- // resumed.
- final int videoResumeTimeoutMs = 1000;
- startTimeMs = System.currentTimeMillis();
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- long resumeVideoTimeUs = -1;
- do {
- assertTrue(String.format("Video has not resumed after %d milliseconds",
- videoResumeTimeoutMs),
- System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
- resumeVideoTimeUs = currentVideoTimeUs;
- Thread.sleep(50);
- currentVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
- } while (currentVideoTimeUs == resumeVideoTimeUs);
+ {
+ // We actually don't care about trying to capture the exact time video resumed, because
+ // we can just look at the historical list of rendered video timestamps
+ long postResumeVideoTimeUs;
+ long previousVideoTimeUs;
+ long startTimeMs = System.currentTimeMillis();
+ do {
+ int videoResumeTimeoutMs = 2000;
+ assertTrue(String.format("Video has not resumed after %d milliseconds",
+ videoResumeTimeoutMs),
+ System.currentTimeMillis() - startTimeMs < videoResumeTimeoutMs);
+ previousVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ Thread.sleep(50);
+ postResumeVideoTimeUs = mMediaCodecPlayer.getVideoTimeUs();
+ } while (postResumeVideoTimeUs == previousVideoTimeUs);
+ }
// The system time when rendering the first audio frame after the resume
long playbackRateFps = mMediaCodecPlayer.getAudioTrack().getPlaybackRate();
@@ -4721,52 +4751,74 @@ public class DecoderTest extends MediaTestBase {
long resumeAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime - (long) elapsedTimeNs;
long resumeAudioSystemTimeMs = resumeAudioSystemTimeNs / 1000 / 1000;
- // The system time when rendering the first video frame after the resume
+ // The system time when rendering the first video frame after video playback resumes
long resumeVideoSystemTimeMs = mMediaCodecPlayer.getRenderedVideoFrameSystemTimeList()
- .get(underrunVideoRenderedTimestampIndex + 1) / 1000 / 1000;
+ .get(pausedVideoRenderedTimestampIndex + 1) / 1000 / 1000;
- // Verify that audio and video are in-sync after resume time
+ // Verify that video resumes in a reasonable amount of time after audio resumes
// Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
resumeAudioSystemTimeMs += 100;
- long vsyncMs = 1000 / frameRate;
- long avSyncOffsetMs = resumeAudioSystemTimeMs - resumeVideoSystemTimeMs;
+ long resumeDeltaMs = resumeVideoSystemTimeMs - resumeAudioSystemTimeMs;
+ assertTrue(String.format("Video started %s milliseconds before audio resumed "
+ + "(video:%d audio:%d)", resumeDeltaMs * -1, resumeVideoSystemTimeMs,
+ resumeAudioSystemTimeMs),
+ resumeDeltaMs > 0); // video is expected to start after audio resumes
assertTrue(String.format(
- "Audio is %d milliseconds out of sync of video (audio:%d video:%d)",
- avSyncOffsetMs, resumeAudioSystemTimeMs, resumeVideoSystemTimeMs),
- Math.abs(avSyncOffsetMs) <= vsyncMs);
+ "Video started %d milliseconds after audio resumed (video:%d audio:%d)",
+ resumeDeltaMs, resumeVideoSystemTimeMs, resumeAudioSystemTimeMs),
+ resumeDeltaMs <= 600); // video starting 300ms after audio is barely noticeable
+
+ // Determine the system time of the audio frame that matches the presentation timestamp of
+ // the resumed video frame
+ long resumeVideoPresentationTimeUs = mMediaCodecPlayer.getRenderedVideoFrameTimestampList()
+ .get(pausedVideoRenderedTimestampIndex + 1);
+ long matchingAudioFramePosition = resumeVideoPresentationTimeUs * playbackRateFps / 1000 / 1000;
+ playedFrames = matchingAudioFramePosition - postResumeAudioTimestamp.framePosition;
+ elapsedTimeNs = playedFrames * (1000.0 * 1000.0 * 1000.0 / playbackRateFps);
+ long matchingAudioSystemTimeNs = postResumeAudioTimestamp.nanoTime + (long) elapsedTimeNs;
+ long matchingAudioSystemTimeMs = matchingAudioSystemTimeNs / 1000 / 1000;
+
+ // Verify that video and audio are in sync at the time when video resumes
+ // Note: Because a -100ms PTS gap is introduced, the video should resume 100ms later
+ matchingAudioSystemTimeMs += 100;
+ long avSyncOffsetMs = resumeVideoSystemTimeMs - matchingAudioSystemTimeMs;
+ assertTrue(String.format("Video is %d milliseconds out of sync of audio after resuming "
+ + "(video:%d, audio:%d)", avSyncOffsetMs, resumeVideoSystemTimeMs,
+ matchingAudioSystemTimeMs),
+ // some leniency in AV sync is required because Android TV STB/OTT OEMs often have
+ // to tune for imperfect downstream TVs (that have processing delays on the video)
+ // by knowingly producing HDMI output that has audio and video mildly out of sync
+ Math.abs(avSyncOffsetMs) <= 80);
}
/**
- * Test tunneled audio underrun with HEVC if supported
+ * Test that audio underrun pauses video and resumes in-sync for HEVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunHevc() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_HEVC,
- "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv",
- 25);
+ "video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
}
/**
- * Test tunneled audio underrun with AVC if supported
+ * Test that audio underrun pauses video and resumes in-sync for AVC in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunAvc() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_AVC,
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
- 25);
+ "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
}
/**
- * Test tunneled audio underrun with VP9 if supported
+ * Test that audio underrun pauses video and resumes in-sync for VP9 in tunneled mode.
*/
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
+ @ApiTest(apis={"android.media.MediaCodecInfo.CodecCapabilities#FEATURE_TunneledPlayback"})
public void testTunneledAudioUnderrunVp9() throws Exception {
tunneledAudioUnderrun(MediaFormat.MIMETYPE_VIDEO_VP9,
- "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm",
- 30);
+ "bbb_s1_640x360_webm_vp9_0p21_1600kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
}
private void sleepUntil(Supplier<Boolean> supplier, Duration maxWait) throws Exception {
diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
index 1a1a46f5383..2c1d9c5edc4 100644
--- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
@@ -26,7 +26,6 @@ import android.media.ResourceBusyException;
import android.media.UnsupportedSchemeException;
import android.media.cts.AudioManagerStub;
import android.media.cts.AudioManagerStubHelper;
-import android.media.cts.CodecState;
import android.media.cts.ConnectionStatus;
import android.media.cts.IConnectionStatus;
import android.media.cts.InputSurface;
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java b/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
index 4afc7aafd2b..74aa214f6d6 100644
--- a/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
+++ b/tests/tests/media/encoder/src/android/media/encoder/cts/VideoEncoderTest.java
@@ -43,6 +43,7 @@ import android.media.cts.NonMediaMainlineTest;
import android.media.cts.OutputSurface;
import android.media.cts.Preconditions;
import android.media.cts.TestArgs;
+import android.media.cts.TestUtils;
import android.net.Uri;
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
@@ -1301,6 +1302,10 @@ public class VideoEncoderTest extends MediaTestBase {
if (TestArgs.shouldSkipCodec(encoder)) {
continue;
}
+ if (!TestUtils.isTestableCodecInCurrentMode(encoder)) {
+ Log.d(TAG, "Skipping tests for codec: " + encoder);
+ continue;
+ }
CodecCapabilities caps = getCodecCapabities(encoder, mediaType, true);
assertNotNull(caps);
EncoderSize encoderSize = new EncoderSize(encoder, mediaType, caps);
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
index 0505d8b5119..5c1ec89be93 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
@@ -282,6 +282,10 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me
mRecorder.reset();
mRecorder.release();
output.write(", " + i);
+ if (mRemoveVideo) {
+ removeRecodedVideo(filename);
+ }
+
}
output.write("\n\n");
@@ -371,6 +375,9 @@ public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<Me
mRecorder.release();
Log.v(TAG, "release video recorder");
output.write(", " + i);
+ if (mRemoveVideo) {
+ removeRecodedVideo(filename);
+ }
}
output.write("\n\n");
diff --git a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
index ec8b7c862c4..f49e06548d6 100644
--- a/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
+++ b/tests/tests/os/src/android/os/cts/AppHibernationUtils.kt
@@ -62,6 +62,10 @@ import org.junit.Assert.assertTrue
private const val BROADCAST_TIMEOUT_MS = 60000L
const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+const val HIBERNATION_BOOT_RECEIVER_CLASS_NAME =
+ "com.android.permissioncontroller.hibernation.HibernationOnBootReceiver"
+const val ACTION_SET_UP_HIBERNATION =
+ "com.android.permissioncontroller.action.SET_UP_HIBERNATION"
const val SYSUI_PKG_NAME = "com.android.systemui"
const val NOTIF_LIST_ID = "com.android.systemui:id/notification_stack_scroller"
@@ -84,35 +88,37 @@ const val APK_PACKAGE_NAME_Q_APP = "android.os.cts.autorevokeqapp"
fun runBootCompleteReceiver(context: Context, testTag: String) {
val pkgManager = context.packageManager
val permissionControllerPkg = pkgManager.permissionControllerPackageName
+ var permissionControllerSetupIntent = Intent(ACTION_SET_UP_HIBERNATION).apply {
+ setPackage(permissionControllerPkg)
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ }
val receivers = pkgManager.queryBroadcastReceivers(
- Intent(Intent.ACTION_BOOT_COMPLETED), /* flags= */ 0)
- for (ri in receivers) {
- val pkg = ri.activityInfo.packageName
- if (pkg == permissionControllerPkg) {
- val permissionControllerSetupIntent = Intent()
- .setClassName(pkg, ri.activityInfo.name)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .setPackage(permissionControllerPkg)
- val countdownLatch = CountDownLatch(1)
- Log.d(testTag, "Sending boot complete broadcast directly to ${ri.activityInfo.name} " +
- "in package $permissionControllerPkg")
- context.sendOrderedBroadcast(
- permissionControllerSetupIntent,
- /* receiverPermission= */ null,
- object : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- countdownLatch.countDown()
- Log.d(testTag, "Broadcast received by $permissionControllerPkg")
- }
- },
- Handler.createAsync(Looper.getMainLooper()),
- Activity.RESULT_OK,
- /* initialData= */ null,
- /* initialExtras= */ null)
- assertTrue("Timed out while waiting for boot receiver broadcast to be received",
- countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
+ permissionControllerSetupIntent, /* flags= */ 0)
+ if (receivers.size == 0) {
+ // May be on an older, pre-built PermissionController. In this case, try sending directly.
+ permissionControllerSetupIntent = Intent().apply {
+ setPackage(permissionControllerPkg)
+ setClassName(permissionControllerPkg, HIBERNATION_BOOT_RECEIVER_CLASS_NAME)
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
}
}
+ val countdownLatch = CountDownLatch(1)
+ Log.d(testTag, "Sending boot complete broadcast directly to $permissionControllerPkg")
+ context.sendOrderedBroadcast(
+ permissionControllerSetupIntent,
+ /* receiverPermission= */ null,
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ countdownLatch.countDown()
+ Log.d(testTag, "Broadcast received by $permissionControllerPkg")
+ }
+ },
+ Handler.createAsync(Looper.getMainLooper()),
+ Activity.RESULT_OK,
+ /* initialData= */ null,
+ /* initialExtras= */ null)
+ assertTrue("Timed out while waiting for boot receiver broadcast to be received",
+ countdownLatch.await(BROADCAST_TIMEOUT_MS, TimeUnit.MILLISECONDS))
}
fun runAppHibernationJob(context: Context, tag: String) {
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index b5db2fd8f76..1d81e4405fb 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -134,7 +134,11 @@ class AutoRevokeTest {
// Wake up the device
runShellCommandOrThrow("input keyevent KEYCODE_WAKEUP")
- runShellCommandOrThrow("input keyevent 82")
+ if ("false".equals(runShellCommandOrThrow("cmd lock_settings get-disabled"))) {
+ // Unlock screen only when it's lock settings enabled to prevent showing "wallpaper
+ // picker" which may cover another UI elements on freeform window configuration.
+ runShellCommandOrThrow("input keyevent 82")
+ }
if (isAutomotiveDevice()) {
supportedApkPath = APK_PATH_S_APP
@@ -459,21 +463,23 @@ class AutoRevokeTest {
// Verify
val safetyCenterManager =
context.getSystemService(SafetyCenterManager::class.java)!!
- val issues = ArrayList<SafetyCenterIssue>()
- runWithShellPermissionIdentity {
- val safetyCenterData = safetyCenterManager!!.safetyCenterData
- issues.addAll(safetyCenterData.issues)
+ eventually {
+ val issues = ArrayList<SafetyCenterIssue>()
+ runWithShellPermissionIdentity {
+ val safetyCenterData = safetyCenterManager!!.safetyCenterData
+ issues.addAll(safetyCenterData.issues)
+ }
+ val issueId = SafetyCenterIds.encodeToString(
+ SafetyCenterIssueId.newBuilder()
+ .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
+ .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
+ .setUserId(UserHandle.myUserId())
+ .build())
+ .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
+ .build())
+ assertTrue(issues.any { it.id == issueId })
}
- val issueId = SafetyCenterIds.encodeToString(
- SafetyCenterIssueId.newBuilder()
- .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
- .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
- .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
- .setUserId(UserHandle.myUserId())
- .build())
- .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
- .build())
- assertTrue(issues.any {it.id == issueId})
}
}
}
@@ -500,21 +506,23 @@ class AutoRevokeTest {
// Verify
val safetyCenterManager =
context.getSystemService(SafetyCenterManager::class.java)!!
- val issues = ArrayList<SafetyCenterIssue>()
- runWithShellPermissionIdentity {
- val safetyCenterData = safetyCenterManager!!.safetyCenterData
- issues.addAll(safetyCenterData.issues)
+ eventually {
+ val issues = ArrayList<SafetyCenterIssue>()
+ runWithShellPermissionIdentity {
+ val safetyCenterData = safetyCenterManager!!.safetyCenterData
+ issues.addAll(safetyCenterData.issues)
+ }
+ val issueId = SafetyCenterIds.encodeToString(
+ SafetyCenterIssueId.newBuilder()
+ .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
+ .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
+ .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
+ .setUserId(UserHandle.myUserId())
+ .build())
+ .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
+ .build())
+ assertFalse(issues.any { it.id == issueId })
}
- val issueId = SafetyCenterIds.encodeToString(
- SafetyCenterIssueId.newBuilder()
- .setSafetyCenterIssueKey(SafetyCenterIssueKey.newBuilder()
- .setSafetySourceId(UNUSED_APPS_SOURCE_ID)
- .setSafetySourceIssueId(UNUSED_APPS_ISSUE_ID)
- .setUserId(UserHandle.myUserId())
- .build())
- .setIssueTypeId(UNUSED_APPS_ISSUE_ID)
- .build())
- assertFalse(issues.any {it.id == issueId})
}
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
index 86a680ecd7f..28d58d65076 100644
--- a/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/AccessibilityPrivacySourceTest.kt
@@ -58,7 +58,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@AppModeFull(
reason = "Cannot set system settings as instant app. Also we never show an accessibility " +
- "notification for instant apps."
+ "notification for instant apps."
)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
class AccessibilityPrivacySourceTest {
@@ -243,12 +243,27 @@ class AccessibilityPrivacySourceTest {
"cmd jobscheduler reset-execution-quota -u " +
"${Process.myUserHandle().identifier} $permissionControllerPackage")
- context.sendBroadcast(
- Intent().apply {
- setClassName(permissionControllerPackage, AccessibilityOnBootReceiver)
- setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ // Setup up permission controller again (simulate a reboot)
+ val permissionControllerSetupIntent =
+ Intent(ACTION_SET_UP_ACCESSIBILITY_CHECK).apply {
setPackage(permissionControllerPackage)
- })
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ }
+
+ // Query for the setup broadcast receiver
+ val resolveInfos =
+ context.packageManager.queryBroadcastReceivers(permissionControllerSetupIntent, 0)
+
+ if (resolveInfos.size > 0) {
+ context.sendBroadcast(permissionControllerSetupIntent)
+ } else {
+ context.sendBroadcast(
+ Intent().apply {
+ setClassName(permissionControllerPackage, AccessibilityOnBootReceiver)
+ setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ setPackage(permissionControllerPackage)
+ })
+ }
// Wait until jobs are set up
TestUtils.eventually(
@@ -288,6 +303,8 @@ class AccessibilityPrivacySourceTest {
private const val AccessibilityOnBootReceiver =
"com.android.permissioncontroller.privacysources.AccessibilityOnBootReceiver"
+ private const val ACTION_SET_UP_ACCESSIBILITY_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_ACCESSIBILITY_CHECK"
@get:ClassRule
@JvmStatic
diff --git a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
index 6ce52b180f4..9daeff2af4a 100644
--- a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
@@ -17,7 +17,6 @@
package android.permission.cts;
import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.os.Process.myUserHandle;
import static android.permission.cts.PermissionUtils.clearAppState;
@@ -114,6 +113,11 @@ public class BaseNotificationListenerCheckTest {
private static final String PROPERTY_JOB_SCHEDULER_RATE_LIMIT_WINDOW_MILLIS =
"qc_rate_limiting_window_ms";
+ private static final String ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_NOTIFICATION_LISTENER_CHECK";
+ private static final String NotificationListenerOnBootReceiver =
+ "com.android.permissioncontroller.privacysources.SetupPeriodicNotificationListenerCheck";
+
/**
* ID for notification shown by
* {@link com.android.permissioncontroller.privacysources.NotificationListenerCheck}.
@@ -374,19 +378,21 @@ public class BaseNotificationListenerCheckTest {
}, UNEXPECTED_TIMEOUT_MILLIS);
// Setup up permission controller again (simulate a reboot)
- Intent permissionControllerSetupIntent = null;
- for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
- new Intent(ACTION_BOOT_COMPLETED), 0)) {
- String pkg = ri.activityInfo.packageName;
-
- if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
- permissionControllerSetupIntent = new Intent()
- .setClassName(pkg, ri.activityInfo.name)
- .setFlags(FLAG_RECEIVER_FOREGROUND)
- .setPackage(PERMISSION_CONTROLLER_PKG);
-
- sContext.sendBroadcast(permissionControllerSetupIntent);
- }
+ Intent permissionControllerSetupIntent = new Intent(
+ ACTION_SET_UP_NOTIFICATION_LISTENER_CHECK).setPackage(
+ PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
+
+ // Query for the setup broadcast receiver
+ List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+ permissionControllerSetupIntent, 0);
+
+ if (resolveInfos.size() > 0) {
+ sContext.sendBroadcast(permissionControllerSetupIntent);
+ } else {
+ sContext.sendBroadcast(new Intent()
+ .setClassName(PERMISSION_CONTROLLER_PKG, NotificationListenerOnBootReceiver)
+ .setFlags(FLAG_RECEIVER_FOREGROUND)
+ .setPackage(PERMISSION_CONTROLLER_PKG));
}
// Wait until jobs are set up
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index b41fb081d39..ceb4ede242b 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -23,7 +23,6 @@ import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_NOT_FOREGROUND;
-import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.location.Criteria.ACCURACY_FINE;
import static android.os.Process.myUserHandle;
@@ -41,7 +40,6 @@ 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 static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -120,6 +118,8 @@ public class LocationAccessCheckTest {
"/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk";
private static final String TEST_APP_LOCATION_FG_ACCESS_APK =
"/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk";
+ private static final String ACTION_SET_UP_LOCATION_ACCESS_CHECK =
+ "com.android.permissioncontroller.action.SET_UP_LOCATION_ACCESS_CHECK";
private static final int LOCATION_ACCESS_CHECK_JOB_ID = 0;
private static final int LOCATION_ACCESS_CHECK_NOTIFICATION_ID = 0;
@@ -153,6 +153,10 @@ public class LocationAccessCheckTest {
private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
.getPermissionControllerPackageName();
+ private static final String LocationAccessCheckOnBootReceiver =
+ "com.android.permissioncontroller.permission.service"
+ + ".LocationAccessCheck$SetupPeriodicBackgroundLocationAccessCheck";
+
/**
* The result of {@link #assumeCanGetFineLocation()}, so we don't have to run it over and over
@@ -389,6 +393,11 @@ public class LocationAccessCheckTest {
* Force a run of the location check.
*/
private static void runLocationCheck() throws Throwable {
+ // If the job isn't setup, do it before running a location check
+ if (!isLocationAccessJobSetup(myUserHandle().getIdentifier())) {
+ setupLocationAccessCheckJob();
+ }
+
// Sleep a little bit to make sure we don't have overlap in timing
Thread.sleep(1000);
@@ -676,36 +685,45 @@ public class LocationAccessCheckTest {
}
}, UNEXPECTED_TIMEOUT_MILLIS);
- // Setup up permission controller again (simulate a reboot)
- Intent permissionControllerSetupIntent = null;
- for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
- new Intent(ACTION_BOOT_COMPLETED), 0)) {
- String pkg = ri.activityInfo.packageName;
-
- if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
- permissionControllerSetupIntent = new Intent()
- .setClassName(pkg, ri.activityInfo.name)
- .setFlags(FLAG_RECEIVER_FOREGROUND)
- .setPackage(PERMISSION_CONTROLLER_PKG);
-
- sContext.sendBroadcast(permissionControllerSetupIntent);
- }
- }
+ setupLocationAccessCheckJob();
// Wait until jobs are set up
eventually(() -> {
- JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+ assertTrue("LocationAccessCheck job not found",
+ isLocationAccessJobSetup(currentUserId));
+ }, UNEXPECTED_TIMEOUT_MILLIS);
+ }
- for (RegisteredJob job : dump.registeredJobs) {
- if (job.dump.sourceUserId == currentUserId
- && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
- && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
- return;
- }
+ private static boolean isLocationAccessJobSetup(int currentUserId) throws Exception {
+ JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+ for (RegisteredJob job : dump.registeredJobs) {
+ if (job.dump.sourceUserId == currentUserId
+ && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)
+ && job.dump.jobInfo.service.className.contains("LocationAccessCheck")) {
+ return true;
}
-
- fail("Permission controller jobs not found");
- }, UNEXPECTED_TIMEOUT_MILLIS);
+ }
+ return false;
+ }
+
+ private static void setupLocationAccessCheckJob() {
+ // Setup location access check
+ Intent permissionControllerSetupIntent = new Intent(
+ ACTION_SET_UP_LOCATION_ACCESS_CHECK).setPackage(
+ PERMISSION_CONTROLLER_PKG).setFlags(FLAG_RECEIVER_FOREGROUND);
+
+ // Query for the setup broadcast receiver
+ List<ResolveInfo> resolveInfos = sContext.getPackageManager().queryBroadcastReceivers(
+ permissionControllerSetupIntent, 0);
+
+ if (resolveInfos.size() > 0) {
+ sContext.sendBroadcast(permissionControllerSetupIntent);
+ } else {
+ sContext.sendBroadcast(new Intent()
+ .setClassName(PERMISSION_CONTROLLER_PKG, LocationAccessCheckOnBootReceiver)
+ .setFlags(FLAG_RECEIVER_FOREGROUND)
+ .setPackage(PERMISSION_CONTROLLER_PKG));
+ }
}
/**
diff --git a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
index 6693aa325e3..8bd15373101 100644
--- a/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/MediaPermissionTest.kt
@@ -20,6 +20,7 @@ import android.Manifest
import android.os.Build
import androidx.test.filters.SdkSuppress
import com.android.compatibility.common.util.SystemUtil
+import org.junit.Assume
import org.junit.Test
/**
@@ -96,6 +97,8 @@ class MediaPermissionTest : BaseUsePermissionTest() {
@Test
fun testWhenVisualIsDeniedManuallyThenShouldDenyAllPermissions() {
+ // TODO: Re-enable after b/239249703 is fixed
+ Assume.assumeFalse("skip on TV due to flaky", isTv)
installPackage(APP_APK_PATH_23)
grantAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
revokeAppPermissions(android.Manifest.permission.READ_MEDIA_VIDEO, targetSdk = 23)
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
index 5355fdc6860..7d0ba798484 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
@@ -45,6 +45,7 @@ private const val MORE_OPTIONS = "More options"
private const val TIMELINE_7_DAYS_DESCRIPTION = "in the past 7 days"
private const val DASHBOARD_7_DAYS_DESCRIPTION = "7 days"
private const val PRIV_DASH_7_DAY_ENABLED = "privacy_dashboard_7_day_toggle"
+private const val REFRESH = "Refresh"
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
class PermissionHistoryTest : BasePermissionHubTest() {
@@ -100,9 +101,22 @@ class PermissionHistoryTest : BasePermissionHubTest() {
waitFindObject(By.textContains(APP_LABEL_1))
openPermissionDashboard()
- waitFindObject(By.res("android:id/title").textContains("Microphone")).click()
- waitFindObject(By.textContains(micLabel))
- waitFindObject(By.textContains(APP_LABEL_1))
+
+ SystemUtil.eventually {
+ try {
+ waitFindObject(By.hasChild(By.textContains("Microphone"))
+ .hasChild(By.textStartsWith("Used by")))
+ .click()
+ waitFindObject(By.textContains(micLabel))
+ waitFindObject(By.textContains(APP_LABEL_1))
+ } catch (e: Exception) {
+ // Sometimes the dashboard was in the state from previous failed tests.
+ // Clicking the refresh button to get the most recent access.
+ waitFindObject(By.descContains(REFRESH)).click()
+ throw e
+ }
+ }
+
pressBack()
pressBack()
}
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index 1e318ea0d73..7c9a6b2adaf 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -1,7 +1,13 @@
-# Bug component: 655625
-
-include platform/frameworks/base:/core/java/android/os/storage/OWNERS
-
tgunn@google.com
nicksauer@google.com
nona@google.com
+
+# Storage team ownership
+
+# Bug component: 655625 = per-file *MediaStore*
+
+per-file *MediaStore* = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file Android.bp = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidManifest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file AndroidTest.xml = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
+per-file OWNERS = file:platform/frameworks/base:/core/java/android/os/storage/OWNERS
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20135.java b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
new file mode 100644
index 00000000000..2789ff85d10
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20135.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20135 extends StsExtraBusinessLogicTestCase {
+
+ @Test
+ @AsbSecurityTest(cveBugId = 220303465)
+ public void testPocCVE_2022_20135() {
+ Bundle bundle = new Bundle();
+ try {
+ Class clazz = Class.forName("android.service.gatekeeper.GateKeeperResponse");
+ assumeNotNull(clazz);
+ Object obj = clazz.getMethod("createGenericResponse", int.class).invoke(null, 0);
+ assumeNotNull(obj);
+ Field field = clazz.getDeclaredField("mPayload");
+ assumeNotNull(field);
+ field.setAccessible(true);
+ field.set(obj, new byte[0]);
+ bundle.putParcelable("1", (Parcelable) obj);
+ bundle.putByteArray("2", new byte[1000]);
+ } catch (Exception ex) {
+ assumeNoException(ex);
+ }
+ Parcel parcel = Parcel.obtain();
+ assumeNotNull(parcel);
+ parcel.writeBundle(bundle);
+ parcel.setDataPosition(0);
+ Bundle newBundle = new Bundle();
+ newBundle.readFromParcel(parcel);
+ newBundle.keySet();
+ }
+}
diff --git a/tests/tests/systemui/Android.bp b/tests/tests/systemui/Android.bp
index e33d8fc7966..3a68e4df1dd 100644
--- a/tests/tests/systemui/Android.bp
+++ b/tests/tests/systemui/Android.bp
@@ -39,6 +39,7 @@ android_test {
"androidx.test.ext.junit",
"androidx.test.uiautomator",
"cts-wm-util",
+ "permission-test-util-lib",
"ub-uiautomator",
],
srcs: [
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index f55ed3f13c5..d4ba3b3d4fe 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- Required by flickerlib to dump window states -->
<uses-permission android:name="android.permission.DUMP"/>
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application android:requestLegacyExternalStorage="true">
<activity android:name=".LightBarActivity"
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index ffa58bafc97..50792176d28 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -16,6 +16,9 @@
package android.systemui.cts;
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
+import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
import static android.server.wm.BarTestUtils.assumeStatusBarContainsCutout;
@@ -33,7 +36,10 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Insets;
+import android.os.Process;
import android.os.SystemClock;
+import android.permission.PermissionManager;
+import android.permission.cts.PermissionUtils;
import android.platform.test.annotations.AppModeFull;
import android.view.Gravity;
import android.view.InputDevice;
@@ -45,6 +51,7 @@ import android.view.WindowMetrics;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.ThrowingRunnable;
import org.junit.Rule;
@@ -244,22 +251,23 @@ public class LightBarTests extends LightBarTestBase {
}
private void runInNotificationSession(ThrowingRunnable task) throws Exception {
+ Context context = getInstrumentation().getContext();
+ String packageName = getInstrumentation().getTargetContext().getPackageName();
try {
- mNm = (NotificationManager) getInstrumentation().getContext()
- .getSystemService(Context.NOTIFICATION_SERVICE);
+ PermissionUtils.grantPermission(packageName, POST_NOTIFICATIONS);
+ mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel1 = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
mNm.createNotificationChannel(channel1);
// post 10 notifications to ensure enough icons in the status bar
for (int i = 0; i < 10; i++) {
- Notification.Builder noti1 = new Notification.Builder(
- getInstrumentation().getContext(),
- NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_save)
- .setChannelId(NOTIFICATION_CHANNEL_ID)
- .setPriority(Notification.PRIORITY_LOW)
- .setGroup(NOTIFICATION_GROUP_KEY);
+ Notification.Builder noti1 =
+ new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_save)
+ .setChannelId(NOTIFICATION_CHANNEL_ID)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setGroup(NOTIFICATION_GROUP_KEY);
mNm.notify(NOTIFICATION_TAG, i, noti1.build());
}
@@ -267,6 +275,16 @@ public class LightBarTests extends LightBarTestBase {
} finally {
mNm.cancelAll();
mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+
+ // Use test API to prevent PermissionManager from killing the test process when revoking
+ // permission.
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> context.getSystemService(PermissionManager.class)
+ .revokePostNotificationPermissionWithoutKillForTest(
+ packageName,
+ Process.myUserHandle().getIdentifier()),
+ REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
+ REVOKE_RUNTIME_PERMISSIONS);
}
}
diff --git a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
deleted file mode 100644
index b74678bc3af..00000000000
--- a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.systemui.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.server.wm.WindowManagerStateHelper;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.Until;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests related MediaOutputDialog:
- *
- * atest MediaDialogTest
- */
-@RunWith(AndroidJUnit4.class)
-public class MediaOutputDialogTest {
-
- private static final int TIMEOUT = 5000;
- private static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
- "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
- private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
- public static final String EXTRA_PACKAGE_NAME = "package_name";
- public static final String TEST_PACKAGE_NAME = "com.android.package.test";
- private static final BySelector MEDIA_DIALOG_SELECTOR = By.res(SYSTEMUI_PACKAGE_NAME,
- "media_output_dialog");
- private WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
-
- private Context mContext;
- private UiDevice mDevice;
- private String mLauncherPackage;
- private boolean mHasTouchScreen;
- private ActivityManager mActivityManager;
- private static final int DURATION_SCREEN_TOGGLE = 2000;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- final PackageManager packageManager = mContext.getPackageManager();
-
- mHasTouchScreen = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
- || packageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
-
- Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
- launcherIntent.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = packageManager.resolveActivity(launcherIntent,
- PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
- assumeFalse("Skipping test: can't get resolve info", resolveInfo == null);
- assumeFalse("Skipping test: not supported on automotive yet",
- packageManager.hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE));
- mLauncherPackage = resolveInfo.activityInfo.packageName;
- mActivityManager = mContext.getSystemService(ActivityManager.class);
- }
-
- @Test
- public void mediaOutputDialog_correctDialog() throws Exception {
- prepareDevice();
- assumeTrue(mHasTouchScreen);
- try {
- if (mActivityManager.isLowRamDevice()) {
- SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
- "appops set " + SYSTEMUI_PACKAGE_NAME + " SYSTEM_ALERT_WINDOW allow");
- }
-
- launchMediaOutputDialog();
-
- assertThat(mDevice.wait(Until.hasObject(MEDIA_DIALOG_SELECTOR), TIMEOUT)).isTrue();
- } finally {
- if (mActivityManager.isLowRamDevice()) {
- SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
- "appops set " + SYSTEMUI_PACKAGE_NAME + " SYSTEM_ALERT_WINDOW ignore");
- }
- }
- }
-
- private void prepareDevice() throws Exception {
- mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- mDevice.executeShellCommand("wm dismiss-keyguard");
- // Since the screen on/off intent is ordered, they will not be sent right now.
- mWmState.waitForKeyguardGone();
- }
-
- private void launchMediaOutputDialog() {
- mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
-
- Intent intent = new Intent();
- intent.setPackage(SYSTEMUI_PACKAGE_NAME)
- .setAction(ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
- .putExtra(EXTRA_PACKAGE_NAME, TEST_PACKAGE_NAME);
-
- mContext.sendBroadcast(intent);
- }
-
-}
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
index 02848c89f46..89e4f4dc2b0 100644
--- a/tests/tests/telephony/OWNERS
+++ b/tests/tests/telephony/OWNERS
@@ -1,2 +1,17 @@
-file:platform/frameworks/opt/telephony:/OWNERS
-
+# Bug component: 20868
+amagup@google.com
+amallampati@google.com
+amruthr@google.com
+breadley@google.com
+chinmayd@google.com
+fionaxu@google.com
+huiwang@google.com
+jackyu@google.com
+jayachandranc@google.com
+linggm@google.com
+rgreenwalt@google.com
+sarahchin@google.com
+sasindran@google.com
+tgunn@google.com
+tjstuart@google.com
+xiaotonj@google.com
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 3757b632d28..d7bc9b15896 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -109,6 +109,7 @@ import android.util.Pair;
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CarrierPrivilegeUtils;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ShellIdentityUtils;
@@ -283,6 +284,7 @@ public class TelephonyManagerTest {
private static final int RADIO_HAL_VERSION_1_3 = makeRadioVersion(1, 3);
private static final int RADIO_HAL_VERSION_1_5 = makeRadioVersion(1, 5);
private static final int RADIO_HAL_VERSION_1_6 = makeRadioVersion(1, 6);
+ private static final int RADIO_HAL_VERSION_2_0 = makeRadioVersion(2, 0);
static {
EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
@@ -1250,43 +1252,70 @@ public class TelephonyManagerTest {
private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
@Test
+ @ApiTest(apis = "android.telephony.TelephonyManager#getNetworkCountryIso")
public void testGetNetworkCountryIso() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
String countryCode = mTelephonyManager.getNetworkCountryIso();
- assertTrue("Country code '" + countryCode + "' did not match "
- + ISO_COUNTRY_CODE_PATTERN,
- Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ ServiceState serviceState = mTelephonyManager.getServiceState();
+ if (serviceState != null && (serviceState.getState()
+ == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+ == ServiceState.STATE_EMERGENCY_ONLY)) {
+ assertTrue("Country code '" + countryCode + "' did not match "
+ + ISO_COUNTRY_CODE_PATTERN,
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ } else {
+ assertTrue("Country code could be empty when out of service",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
+ }
- for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
- SubscriptionInfo subscriptionInfo =
- mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(i);
- if (subscriptionInfo != null) {
- countryCode = mTelephonyManager.getNetworkCountryIso(i);
+ int[] allSubs = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager, (sm) -> sm.getActiveSubscriptionIdList());
+ for (int i : allSubs) {
+ countryCode = mTelephonyManager.getNetworkCountryIso(
+ SubscriptionManager.getSlotIndex(i));
+ serviceState = mTelephonyManager.createForSubscriptionId(i).getServiceState();
+
+ if (serviceState != null && (serviceState.getState()
+ == ServiceState.STATE_IN_SERVICE || serviceState.getState()
+ == ServiceState.STATE_EMERGENCY_ONLY)) {
assertTrue("Country code '" + countryCode + "' did not match "
- + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
+ + ISO_COUNTRY_CODE_PATTERN + " for slot " + i,
Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode));
+ } else {
+ assertTrue("Country code could be empty when out of service",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
}
}
+
+ for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
+ countryCode = mTelephonyManager.getNetworkCountryIso(i);
+ assertTrue("Country code must match " + ISO_COUNTRY_CODE_PATTERN + "or empty",
+ Pattern.matches(ISO_COUNTRY_CODE_PATTERN, countryCode)
+ || TextUtils.isEmpty(countryCode));
+ }
}
@Test
public void testSetSystemSelectionChannels() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
List<RadioAccessSpecifier> channels;
try {
- channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, TelephonyManager::getSystemSelectionChannels);
+ uiAutomation.adoptShellPermissionIdentity();
+ channels = mTelephonyManager.getSystemSelectionChannels();
} catch (IllegalStateException e) {
// TODO (b/189255895): Allow ISE once API is enforced in IRadio 2.1.
Log.d(TAG, "Skipping test since system selection channels are not available.");
return;
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
}
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
try {
uiAutomation.adoptShellPermissionIdentity();
// This is a oneway binder call, meaning we may return before the permission check
@@ -1303,20 +1332,29 @@ public class TelephonyManagerTest {
uiAutomation.dropShellPermissionIdentity();
}
+ uiAutomation.adoptShellPermissionIdentity();
+
// Try calling the API that doesn't provide feedback. We have no way of knowing if it
// succeeds, so just make sure nothing crashes.
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
+ mTelephonyManager.setSystemSelectionChannels(Collections.emptyList());
// Assert that we get back the value we set.
- assertEquals(Collections.emptyList(),
- ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- TelephonyManager::getSystemSelectionChannels));
+ assertEquals(Collections.emptyList(), mTelephonyManager.getSystemSelectionChannels());
- // Reset the values back to the original.
- List<RadioAccessSpecifier> finalChannels = channels;
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- tp -> tp.setSystemSelectionChannels(finalChannels));
+ try {
+ // Reset the values back to the original. Use callback to ensure we don't drop
+ // the shell permission until the original state is restored.
+ mTelephonyManager.setSystemSelectionChannels(channels,
+ getContext().getMainExecutor(), queue::offer);
+ Boolean result = queue.poll(1000, TimeUnit.MILLISECONDS);
+ if (result == null || !result) {
+ Log.e(TAG, "Invalid response when resetting initial system selection channels.");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while resetting initial system selection channels.");
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
}
@Test
@@ -1729,6 +1767,10 @@ public class TelephonyManagerTest {
@Test
public void testRebootRadio() throws Throwable {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+ if (mRadioVersion <= RADIO_HAL_VERSION_2_0) {
+ Log.d(TAG, "Skipping test since rebootModem is not supported.");
+ return;
+ }
TestThread t = new TestThread(() -> {
Looper.prepare();
diff --git a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
index 1f7af462bde..94fc6985c0f 100644
--- a/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
+++ b/tests/tests/uidmigration/src/android/uidmigration/cts/SharedUserMigrationTest.kt
@@ -87,6 +87,11 @@ class SharedUserMigrationTest {
assertTrue(pkgs.sameAs(Const.INSTALL_TEST_PKG2))
pkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
assertNull(pkgInfo.sharedUserId)
+ // Upgrading an APK with sharedUserMaxSdkVersion set should not change its UID.
+ assertTrue(installPackage(InstallTest.APK4))
+ val newPkgInfo = mPm.getPackageInfo(Const.INSTALL_TEST_PKG, FLAG_ZERO)
+ assertNull(newPkgInfo.sharedUserId)
+ assertEquals(pkgInfo.applicationInfo.uid, newPkgInfo.applicationInfo.uid)
}
private fun testBestEffort(uid: Int) {
diff --git a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
index a4ef244f232..e0c172ab7db 100644
--- a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
@@ -21,12 +21,17 @@ import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
import android.graphics.Color;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.UiDevice;
import android.view.Gravity;
+import android.view.InputEvent;
+import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.MediumTest;
@@ -40,7 +45,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+// @AppModeFull because GestureNavRule does not work for
+// instant mode tests (b/238975931)
@MediumTest
+@AppModeFull
@RunWith(AndroidJUnit4.class)
public class BackInvokedOnWidgetsTest {
@@ -93,7 +101,45 @@ public class BackInvokedOnWidgetsTest {
private void doBackGesture() {
int midHeight = mUiDevice.getDisplayHeight() / 2;
int midWidth = mUiDevice.getDisplayWidth() / 2;
- mUiDevice.swipe(0, midHeight, midWidth, midHeight, 100);
+ quickSwipe(0, midHeight, midWidth, midHeight, 10);
mUiDevice.waitForIdle();
}
+
+ private void injectInputEventUnSynced(@NonNull InputEvent event) {
+ mInstrumentation.getUiAutomation().injectInputEvent(event, false /* sync */,
+ false /* waitForAnimations */);
+ }
+
+ /**
+ * Injecting a sequence of motion event to simulate swipe without waiting for sync transaction.
+ */
+ private void quickSwipe(float startX, float startY, float endX, float endY, int steps) {
+ if (steps <= 0) {
+ steps = 1;
+ }
+ final long startDownTime = SystemClock.uptimeMillis();
+ MotionEvent firstDown = MotionEvent.obtain(startDownTime, startDownTime,
+ MotionEvent.ACTION_DOWN, startX, startY, 0);
+ injectInputEventUnSynced(firstDown);
+
+ // inject in every 5 ms.
+ final int delayMillis = 5;
+ long nextEventTime = startDownTime + delayMillis;
+ final float stepGapX = (endX - startX) / steps;
+ final float stepGapY = (endY - startY) / steps;
+ for (int i = 0; i < steps; i++) {
+ SystemClock.sleep(delayMillis);
+ final float nextX = startX + stepGapX * i;
+ final float nextY = startY + stepGapY * i;
+ MotionEvent move = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_MOVE, nextX, nextY, 0);
+ injectInputEventUnSynced(move);
+ nextEventTime += delayMillis;
+ }
+
+ SystemClock.sleep(delayMillis);
+ MotionEvent up = MotionEvent.obtain(startDownTime, nextEventTime,
+ MotionEvent.ACTION_UP, endX, endY, 0);
+ injectInputEventUnSynced(up);
+ }
}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index a054aa55bf5..464a24b6b41 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -5519,7 +5519,6 @@ public class WifiManagerTest extends WifiJUnit3TestBase {
waitForConnection();
wifiInfo = mWifiManager.getConnectionInfo();
assertEquals(networkId, wifiInfo.getNetworkId());
- assertEquals(connectedBssid, wifiInfo.getBSSID());
} finally {
// Reset BSSID allow list to accept all APs
for (WifiConfiguration network : savedNetworks) {