summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-30 05:27:45 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-30 05:27:45 +0000
commitd5fdd2bac509340c67ca38185965d97eb8bb1c23 (patch)
treebdcb4a2faee8f6d636218f37db233d52f1260dff
parent73ed9155c17d245d03269125b75cc108f82e1ac9 (diff)
parent87dfd3179a0c5753b007e6daee16a4e9165a5408 (diff)
downloadcts-android13-mainline-cellbroadcast-release.tar.gz
Snap for 9847922 from 87dfd3179a0c5753b007e6daee16a4e9165a5408 to mainline-cellbroadcast-releaseaml_cbr_331810000android13-mainline-cellbroadcast-release
Change-Id: Ieac6d670c370cec2dccb351efa15cfbf05d6fbf5
-rw-r--r--apps/CameraITS/tests/its_base_test.py7
-rw-r--r--apps/CameraITS/tests/scene6/test_zoom.py35
-rwxr-xr-xapps/CameraITS/tools/run_all_tests.py7
-rw-r--r--apps/CameraITS/utils/capture_request_utils.py2
-rw-r--r--apps/CameraITS/utils/its_session_utils.py30
-rw-r--r--apps/CtsVerifier/AndroidManifest.xml5
-rw-r--r--apps/CtsVerifier/res/values-watch/strings.xml3
-rw-r--r--apps/CtsVerifier/res/values/strings.xml1
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java15
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java10
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java15
-rw-r--r--[-rwxr-xr-x]apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java2
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java2
-rw-r--r--apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationPrivacyVerifierActivity.java27
-rw-r--r--hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java6
-rw-r--r--hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java10
-rw-r--r--hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java10
-rw-r--r--hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java21
-rw-r--r--hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java9
-rw-r--r--hostsidetests/incident/AndroidTest.xml3
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java97
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java30
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java54
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java87
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java6
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20955.java81
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp24
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml31
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.pngbin0 -> 9670 bytes
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java126
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp33
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java208
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp4
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml4
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_pkeybin0 -> 634 bytes
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_usercertbin0 -> 732 bytes
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml2
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml49
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml5
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java457
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java26
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java5
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java14
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java2
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp38
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml23
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java119
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/Android.bp54
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/AndroidManifest.xml33
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/values/strings.xml29
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/xml/device_policies.xml20
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/DeviceTest.java131
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/PocDeviceAdminReceiver.java22
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-helper-app/AndroidManifest.xml20
-rw-r--r--hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java8
-rw-r--r--libs/webkit-shared/src/android/webkit/cts/ExceptionWrapper.java95
-rw-r--r--libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java143
-rw-r--r--libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java268
-rw-r--r--tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTestUtils.java52
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java157
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java4
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java48
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java37
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PickerProviderMediaGenerator.java3
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java23
-rw-r--r--tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java8
-rw-r--r--tests/app/Android.bp1
-rw-r--r--tests/app/app/AndroidManifest.xml5
-rw-r--r--tests/app/app/src/android/app/stubs/RemoteActivity.java63
-rw-r--r--tests/app/src/android/app/cts/ActivityManagerTest.java123
-rw-r--r--tests/app/src/android/app/cts/NotificationTemplateTest.kt3
-rw-r--r--tests/autofillservice/res/layout/scrollable_login_activity.xml39
-rw-r--r--tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java5
-rw-r--r--tests/autofillservice/src/android/autofillservice/cts/activities/OutOfProcessLoginActivity.java2
-rw-r--r--tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java40
-rwxr-xr-xtests/framework/base/windowmanager/app/AndroidManifest.xml5
-rw-r--r--tests/framework/base/windowmanager/app/res/values-watch/styles.xml26
-rw-r--r--tests/framework/base/windowmanager/app/res/values/styles.xml3
-rw-r--r--tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java91
-rw-r--r--tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java16
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java5
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java34
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/ConfigChangeTests.java18
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/ForceRelayoutTestBase.java14
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java107
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java1
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/SnapshotTaskTests.java7
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java37
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java12
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java4
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java18
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java2
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java32
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java2
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java6
-rw-r--r--tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java6
-rw-r--r--tests/media/src/android/mediav2/cts/CodecInfoTest.java32
-rw-r--r--tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java5
-rw-r--r--tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java13
-rw-r--r--tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSelfManagedTest.kt2
-rw-r--r--tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSingleDeviceTest.kt2
-rw-r--r--tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndTest.kt2
-rw-r--r--tests/tests/content/src/android/content/pm/cts/FeatureTest.java18
-rw-r--r--tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java48
-rw-r--r--tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java32
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java206
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/CipherTest.java11
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java4
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java9
-rw-r--r--tests/tests/media/audio/src/android/media/audio/cts/AudioManagerTest.java2
-rw-r--r--tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java14
-rw-r--r--tests/tests/networksecurityconfig/src/android/security/net/config/cts/BaseTestCase.java15
-rw-r--r--tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java6
-rw-r--r--tests/tests/permission/src/android/permission/cts/NoWifiStatePermissionTest.java73
-rw-r--r--tests/tests/permission2/res/raw/wear_android_manifest.xml52
-rw-r--r--tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java3
-rw-r--r--tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt19
-rw-r--r--tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt24
-rw-r--r--tests/tests/permission3/CreateNotificationChannelsApp33/Android.bp2
-rw-r--r--tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt1
-rw-r--r--tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt1
-rw-r--r--tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java3
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java71
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java61
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java46
-rw-r--r--tests/tests/security/Android.bp22
-rw-r--r--tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl1
-rw-r--r--tests/tests/security/res/values/strings.xml7
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20338.java73
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2023_21087.java68
-rw-r--r--tests/tests/security/src/android/security/cts/IsolatedProcessTest.java25
-rw-r--r--tests/tests/security/src/android/security/cts/IsolatedService.java9
-rw-r--r--tests/tests/systemui/AndroidManifest.xml8
-rw-r--r--tests/tests/systemui/src/android/systemui/cts/LightBarTests.java26
-rw-r--r--tests/tests/telecom/AndroidManifest.xml7
-rw-r--r--tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java53
-rw-r--r--tests/tests/telecom/src/android/telecom/cts/NullBindingCallRedirectionServiceController.java70
-rw-r--r--tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java4
-rw-r--r--tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt4
-rw-r--r--tests/tests/view/src/android/view/cts/OWNERS1
-rw-r--r--tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java3
-rw-r--r--tests/tests/view/src/android/view/cts/SetTouchableRegionTest.java31
-rw-r--r--tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java66
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java7
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java36
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java34
-rw-r--r--tests/tests/widget/res/values/styles.xml2
-rw-r--r--tests/tests/widget/res/values/themes.xml2
-rw-r--r--tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java24
-rwxr-xr-xtests/tests/widget/src/android/widget/cts/SpinnerTest.java61
-rw-r--r--tests/tests/widget/src/android/widget/cts/ToastTest.java5
-rw-r--r--tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java1
-rwxr-xr-xtools/cts-tradefed/etc/cts-tradefed3
-rw-r--r--tools/cts-tradefed/res/config/cts-known-failures.xml5
-rw-r--r--tools/cts-tradefed/res/config/cts-system.xml30
157 files changed, 3961 insertions, 1185 deletions
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 1a30ac293f2..c0b8665cbc9 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -103,6 +103,13 @@ class ItsBaseTest(base_test.BaseTestClass):
try:
self.tablet = devices[1]
self.tablet_screen_brightness = self.user_params['brightness']
+ tablet_name_unencoded = self.tablet.adb.shell(
+ ['getprop', 'ro.build.product']
+ )
+ tablet_name = str(tablet_name_unencoded.decode('utf-8')).strip()
+ logging.debug('tablet name: %s', tablet_name)
+ its_session_utils.validate_tablet_brightness(
+ tablet_name, self.tablet_screen_brightness)
except KeyError:
logging.debug('Not all tablet arguments set.')
else: # sensor_fusion or manual run
diff --git a/apps/CameraITS/tests/scene6/test_zoom.py b/apps/CameraITS/tests/scene6/test_zoom.py
index fbc882e22a7..2b211babc27 100644
--- a/apps/CameraITS/tests/scene6/test_zoom.py
+++ b/apps/CameraITS/tests/scene6/test_zoom.py
@@ -38,7 +38,7 @@ MIN_CIRCLE_PTS = 25
MIN_FOCUS_DIST_TOL = 0.80 # allow charts a little closer than min
NAME = os.path.splitext(os.path.basename(__file__))[0]
NUM_STEPS = 10
-OFFSET_LOW_VAL = 10 # number of pixels
+OFFSET_ATOL = 10 # number of pixels
OFFSET_RTOL = 0.15
OFFSET_RTOL_LOW_OFFSET = 0.20
OFFSET_RTOL_MIN_FD = 0.30
@@ -207,6 +207,7 @@ class ZoomTest(its_base_test.ItsBaseTest):
def test_zoom(self):
test_data = {}
+ test_failed = False
with its_session_utils.ItsSession(
device_id=self.dut.serial,
camera_id=self.camera_id,
@@ -310,10 +311,10 @@ class ZoomTest(its_base_test.ItsBaseTest):
for i, data in test_data.items():
logging.debug('Zoom: %.2f, fl: %.2f', data['z'], data['fl'])
- offset_abs = [(data['circle'][0] - size[0] // 2),
- (data['circle'][1] - size[1] // 2)]
+ offset_xy = [(data['circle'][0] - size[0] // 2),
+ (data['circle'][1] - size[1] // 2)]
logging.debug('Circle r: %.1f, center offset x, y: %d, %d',
- data['circle'][2], offset_abs[0], offset_abs[1])
+ data['circle'][2], offset_xy[0], offset_xy[1])
z_ratio = data['z'] / z_0
# check relative size against zoom[0]
@@ -326,20 +327,24 @@ class ZoomTest(its_base_test.ItsBaseTest):
# check relative offset against init vals w/ no focal length change
if i == 0 or test_data[i-1]['fl'] != data['fl']: # set init values
z_init = float(data['z'])
- offset_init = [(data['circle'][0] - size[0] // 2),
- (data['circle'][1] - size[1] // 2)]
+ offset_hypot_init = math.hypot(offset_xy[0], offset_xy[1])
+ logging.debug('offset_hypot_init: %.3f', offset_hypot_init)
else: # check
z_ratio = data['z'] / z_init
- offset_rel = (distance(offset_abs[0], offset_abs[1]) / z_ratio /
- distance(offset_init[0], offset_init[1]))
- logging.debug('offset_rel: %.3f', offset_rel)
+ offset_hypot_rel = math.hypot(offset_xy[0], offset_xy[1]) / z_ratio
+ logging.debug('offset_hypot_rel: %.3f', offset_hypot_rel)
rel_tol = data['o_tol']
- if (np.linalg.norm(offset_init) < OFFSET_LOW_VAL and
- rel_tol == OFFSET_RTOL):
- rel_tol = OFFSET_RTOL_LOW_OFFSET
- if not math.isclose(offset_rel, 1.0, rel_tol=rel_tol):
- raise AssertionError(f"zoom: {data['z']:.2f}, offset(rel to 1): "
- f'{offset_rel:.4f}, RTOL: {rel_tol}')
+ if not math.isclose(offset_hypot_init, offset_hypot_rel,
+ rel_tol=rel_tol, abs_tol=OFFSET_ATOL):
+ test_failed = True
+ e_msg = (f"zoom: {data['z']:.2f}, "
+ f'offset init: {offset_hypot_init:.4f}, '
+ f'offset rel: {offset_hypot_rel:.4f}, '
+ f'RTOL: {rel_tol}, ATOL: {OFFSET_ATOL}')
+ logging.error(e_msg)
+
+ if test_failed:
+ raise AssertionError(f'{NAME} failed! Check test_log.DEBUG for errors')
if __name__ == '__main__':
test_runner.main()
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index a75ce5e8b17..ed3d50d2e0a 100755
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -475,6 +475,13 @@ def main():
config_file_test_key = config_file_contents['TestBeds'][0]['Name'].lower()
if TEST_KEY_TABLET in config_file_test_key:
tablet_id = get_device_serial_number('tablet', config_file_contents)
+ tablet_name_cmd = f'adb -s {tablet_id} shell getprop ro.build.product'
+ raw_output = subprocess.check_output(
+ tablet_name_cmd, stderr=subprocess.STDOUT, shell=True)
+ tablet_name = str(raw_output.decode('utf-8')).strip()
+ logging.debug('Tablet name: %s', tablet_name)
+ brightness = test_params_content['brightness']
+ its_session_utils.validate_tablet_brightness(tablet_name, brightness)
else:
tablet_id = None
diff --git a/apps/CameraITS/utils/capture_request_utils.py b/apps/CameraITS/utils/capture_request_utils.py
index 2887925e26b..521ec8442b5 100644
--- a/apps/CameraITS/utils/capture_request_utils.py
+++ b/apps/CameraITS/utils/capture_request_utils.py
@@ -173,7 +173,7 @@ def get_available_output_sizes(fmt, props, max_size=None, match_ar_size=None):
out_sizes = [(cfg['width'], cfg['height']) for cfg in out_configs]
if max_size:
out_sizes = [
- s for s in out_sizes if s[0] <= max_size[0] and s[1] <= max_size[1]
+ s for s in out_sizes if s[0] <= int(max_size[0]) and s[1] <= int(max_size[1])
]
if match_ar_size:
ar = match_ar_size[0] / float(match_ar_size[1])
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index b1fb77a72c3..3caad99137a 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -38,6 +38,15 @@ import opencv_processing_utils
ANDROID13_API_LEVEL = 33
LOAD_SCENE_DELAY_SEC = 3
SUB_CAMERA_SEPARATOR = '.'
+DEFAULT_TABLET_BRIGHTNESS = 192 # 8-bit tablet 75% brightness
+ELEVEN_BIT_TABLET_BRIGHTNESS = 1536
+ELEVEN_BIT_TABLET_NAMES = ('nabu',)
+LEGACY_TABLET_BRIGHTNESS = 96
+LEGACY_TABLET_NAME = 'dragon'
+TABLET_REQUIREMENTS_URL = 'https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-requirements'
+BRIGHTNESS_ERROR_MSG = ('Tablet brightness not set as per '
+ f'{TABLET_REQUIREMENTS_URL} in the config file')
+
_VALIDATE_LIGHTING_PATCH_H = 0.05
_VALIDATE_LIGHTING_PATCH_W = 0.05
_VALIDATE_LIGHTING_REGIONS = {
@@ -50,6 +59,27 @@ _VALIDATE_LIGHTING_REGIONS = {
_VALIDATE_LIGHTING_THRESH = 0.05 # Determined empirically from scene[1:6] tests
+def validate_tablet_brightness(tablet_name, brightness):
+ """Ensures tablet brightness is set according to documentation.
+
+ https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-requirements
+ Args:
+ tablet_name: tablet product name specified by `ro.build.product`.
+ brightness: brightness specified by config file.
+ """
+ name_to_brightness = {
+ LEGACY_TABLET_NAME: LEGACY_TABLET_BRIGHTNESS,
+ }
+ for name in ELEVEN_BIT_TABLET_NAMES:
+ name_to_brightness[name] = ELEVEN_BIT_TABLET_BRIGHTNESS
+ if tablet_name in name_to_brightness:
+ if brightness != name_to_brightness[tablet_name]:
+ raise AssertionError(BRIGHTNESS_ERROR_MSG)
+ else:
+ if brightness != DEFAULT_TABLET_BRIGHTNESS:
+ raise AssertionError(BRIGHTNESS_ERROR_MSG)
+
+
class ItsSession(object):
"""Controls a device over adb to run ITS scripts.
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 6c464b1bad3..595fcc1b2d3 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -271,6 +271,8 @@
android:value="multi_display_mode" />
<meta-data android:name="ApiTest"
android:value="android.companion.CompanionDeviceManager#associate" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.watch" />
</activity>
<activity android:name=".companion.CompanionDeviceServiceTestActivity"
@@ -288,6 +290,8 @@
android:value="multi_display_mode" />
<meta-data android:name="ApiTest"
android:value="android.companion.CompanionDeviceManager#startObservingDevicePresence|android.companion.CompanionDeviceManager#stopObservingDevicePresence" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.watch" />
</activity>
<service
@@ -5357,6 +5361,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_audio" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.hdmi.cec" />
<meta-data android:name="display_mode" android:value="multi_display_mode" />
<meta-data android:name="ApiTest"
android:value="android.media.AudioDescriptor#getStandard|
diff --git a/apps/CtsVerifier/res/values-watch/strings.xml b/apps/CtsVerifier/res/values-watch/strings.xml
index e594b9e37ea..4f412bfc6dc 100644
--- a/apps/CtsVerifier/res/values-watch/strings.xml
+++ b/apps/CtsVerifier/res/values-watch/strings.xml
@@ -61,4 +61,7 @@
7) Repeat steps (1) through (6) for each screen lock type other than \"None\".
</string>
<string name="usb_tapjacking_usb_debugging_component">com.google.android.apps.wearable.settings/com.google.android.clockwork.settings.SecureAdbActivityAlias</string>
+
+ <!-- Adjusted for watches to leave out second part, since not applicable to watches. -->
+ <string name="add_screen_lock">Add a secure screen lock of any type.</string>
</resources>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index c4b65a54c6d..ad1bfd5b26c 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -5772,6 +5772,7 @@ Follow the instructions on the screen to measure the frequency response for the
<string name="audio_tap2tone_too_few">Not enough edges. Use fingernail.</string>
<string name="audio_tap2tone_too_many">Too many edges. Use fingernail. Ensure there is
no background noise.</string>
+ <string name="audio_tap2tone_bad_streams">Can\'t open streams.</string>
<!-- Strings for 6DoF test -->
<string name="six_dof_test">6DoF Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 8ecd14a0870..3b207b3de50 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -154,7 +154,9 @@ public class AnalogHeadsetAudioActivity
mHeadsetVolUpText = (TextView)findViewById(R.id.headset_keycode_volume_up);
mHeadsetVolDownText = (TextView)findViewById(R.id.headset_keycode_volume_down);
- if (isTelevision()) {
+ mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+
+ if (isTelevisionOrFixedVolume()) {
mButtonsPromptTxt.setVisibility(View.GONE);
mHeadsetHookText.setVisibility(View.GONE);
mHeadsetVolUpText.setVisibility(View.GONE);
@@ -164,8 +166,6 @@ public class AnalogHeadsetAudioActivity
mResultsTxt = (TextView)findViewById(R.id.headset_results);
- mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
-
setupPlayer();
mAudioManager.registerAudioDeviceCallback(new ConnectListener(), new Handler());
@@ -177,7 +177,7 @@ public class AnalogHeadsetAudioActivity
showKeyMessagesState();
- setInfoResources(R.string.analog_headset_test, isTelevision()
+ setInfoResources(R.string.analog_headset_test, isTelevisionOrFixedVolume()
? R.string.analog_headset_test_info_tv : R.string.analog_headset_test_info, -1);
setPassFailButtonClickListeners();
@@ -195,7 +195,7 @@ public class AnalogHeadsetAudioActivity
boolean pass = mPlugIntentReceived &&
mHeadsetDeviceInfo != null &&
mPlaybackSuccess &&
- (isTelevision()
+ (isTelevisionOrFixedVolume()
|| ((mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown));
if (pass) {
mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass));
@@ -499,7 +499,8 @@ public class AnalogHeadsetAudioActivity
return super.onKeyDown(keyCode, event);
}
- private boolean isTelevision() {
- return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ private boolean isTelevisionOrFixedVolume() {
+ return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ || mAudioManager.isVolumeFixed();
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 3c1b8a1151e..793b6741bd3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -316,11 +316,15 @@ public class AudioAEC extends AudioFrequencyActivity implements View.OnClickList
setLevelForStream(playbackStreamType, desiredLevel);
int currentLevel = getLevelForStream(playbackStreamType);
- if (currentLevel != desiredLevel) {
+ if (am.isVolumeFixed()) {
+ sendMessage(AudioTestRunner.TEST_MESSAGE,
+ "configured for Fixed volume, bypassing volume level check");
+
+ } else if (currentLevel != desiredLevel) {
am.setMode(originalMode);
sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
- "Couldn't set level for STREAM_VOICE_CALL. Expected " +
- desiredLevel +" got: " + currentLevel);
+ "Couldn't set level for STREAM_VOICE_CALL. Expected " +
+ desiredLevel +" got: " + currentLevel);
return;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
index cf09a74e062..c61689c9110 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
@@ -44,6 +44,7 @@ import com.android.cts.verifier.audio.audiolib.WaveformView;
import com.android.cts.verifier.audio.sources.BlipAudioSourceProvider;
import org.hyphonate.megaaudio.common.BuilderBase;
+import org.hyphonate.megaaudio.common.StreamBase;
import org.hyphonate.megaaudio.duplex.DuplexAudioManager;
import org.hyphonate.megaaudio.player.AudioSource;
import org.hyphonate.megaaudio.player.AudioSourceProvider;
@@ -270,12 +271,18 @@ public class AudioTap2ToneActivity
mDuplexAudioManager.setNumRecorderChannels(NUM_RECORD_CHANNELS);
}
- mDuplexAudioManager.setupStreams(mPlayerType, BuilderBase.TYPE_JAVA);
- mDuplexAudioManager.start();
+ if (mDuplexAudioManager.setupStreams(BuilderBase.TYPE_OBOE, BuilderBase.TYPE_JAVA)
+ == StreamBase.OK) {
+ mDuplexAudioManager.start();
- mBlipSource = (AudioSource) mDuplexAudioManager.getAudioSource();
+ mBlipSource = (AudioSource) mDuplexAudioManager.getAudioSource();
- mIsRecording = true;
+ mIsRecording = true;
+ mResultsView.setText("Successfully opened streams");
+ } else {
+ mIsRecording = false;
+ mResultsView.setText(getString(R.string.audio_tap2tone_bad_streams));
+ }
enableAudioButtons();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
index 793cbf7954d..c8cd8fd50b5 100755..100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/formats/CameraFormatsActivity.java
@@ -653,7 +653,7 @@ public class CameraFormatsActivity extends PassFailButtons.Activity
rotation = (360 - rotation) % 360; // de-compensate the mirror
}
- if (rotation != 0) {
+ if (rotation != 0 && rotation != 180) {
Matrix transform = new Matrix();
mFormatView.setScaleType(ImageView.ScaleType.MATRIX);
Rect viewRect = mFormatView.getDrawable().getBounds();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index eddd930ac30..a7b58fa27cf 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -96,7 +96,7 @@ public final class FeatureUtil {
/**
* Checks whether the device is watch .
*/
- private static boolean isWatch(Context context) {
+ public static boolean isWatch(Context context) {
PackageManager pm = context.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationPrivacyVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationPrivacyVerifierActivity.java
index 760bd71bc77..6c6303773c3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationPrivacyVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationPrivacyVerifierActivity.java
@@ -29,7 +29,6 @@ import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -39,6 +38,7 @@ import android.view.ViewGroup;
import androidx.annotation.StringRes;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.features.FeatureUtil;
import java.util.ArrayList;
import java.util.List;
@@ -105,12 +105,14 @@ public class NotificationPrivacyVerifierActivity extends InteractiveVerifierActi
@Override
protected List<InteractiveTestCase> createTestItems() {
- boolean isAutomotive = getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE);
List<InteractiveTestCase> tests = new ArrayList<>();
- if (!isAutomotive) {
- // FIRST: set redaction settings
- tests.add(new SetScreenLockEnabledStep());
+
+ // FIRST: enable lock screen
+ tests.add(new SetScreenLockEnabledStep());
+
+ // for watches, no notifications should appear on the secure lock screen
+ if (!FeatureUtil.isWatch(this)) {
+ // THEN: set redaction settings
tests.add(new SetGlobalVisibilityPublicStep());
tests.add(new SetChannelLockscreenVisibilityPrivateStep());
// NOW TESTING: redacted by channel
@@ -132,13 +134,16 @@ public class NotificationPrivacyVerifierActivity extends InteractiveVerifierActi
tests.add(new NotificationWhenOccludedShowsRedactedTest());
tests.add(new SetGlobalVisibilitySecretStep());
- // NOW TESTING: notifications do not appear
- tests.add(new NotificationWhenLockedIsHiddenTest());
- tests.add(new NotificationWhenOccludedIsHiddenTest());
+ }
- // FINALLY: restore device state
- tests.add(new SetScreenLockDisabledStep());
+ // NOW TESTING: notifications do not appear
+ tests.add(new NotificationWhenLockedIsHiddenTest());
+ if (!FeatureUtil.isWatch(this)) {
+ tests.add(new NotificationWhenOccludedIsHiddenTest());
}
+
+ // FINALLY: restore device state
+ tests.add(new SetScreenLockDisabledStep());
return tests;
}
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 46f1b478230..4ba312f2bab 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -879,7 +879,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
*/
@Test
public void testBootclasspath_nonDuplicateClasses() throws Exception {
- assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
assertThat(getDuplicateClasses(sBootclasspathJars)).isEmpty();
}
@@ -888,7 +888,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
*/
@Test
public void testSystemServerClasspath_nonDuplicateClasses() throws Exception {
- assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
ImmutableSet<String> overlapBurndownList;
if (hasFeature(FEATURE_AUTOMOTIVE)) {
overlapBurndownList = ImmutableSet.copyOf(AUTOMOTIVE_HIDL_OVERLAP_BURNDOWN_LIST);
@@ -910,7 +910,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
*/
@Test
public void testBootClasspathAndSystemServerClasspath_nonDuplicateClasses() throws Exception {
- assumeTrue(mDeviceSdkLevel.isDeviceAtLeastR());
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
ImmutableList.Builder<String> jars = ImmutableList.builder();
jars.addAll(sBootclasspathJars);
jars.addAll(sSystemserverclasspathJars);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
index e4508a98625..f63f257ba48 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
@@ -98,6 +98,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_ManagedProfile_Success() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
if (!getDevice().hasFeature("android.software.managed_users")) {
CLog.v(TAG, "Device doesn't support managed users; skipping test");
@@ -139,6 +140,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_TwoUsers_SingleUserUnlock_Success() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
if (!mSupportsMultiUser) {
CLog.v(TAG, "Device doesn't support multi-user; skipping test");
@@ -191,6 +193,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_TwoUsers_BothUserUnlock_Success() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
if (!mSupportsMultiUser) {
CLog.v(TAG, "Device doesn't support multi-user; skipping test");
@@ -245,6 +248,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_SingleUser_ServerBased_Success() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
int[] users = Utils.prepareSingleUser(getDevice());
int initialUser = users[0];
@@ -278,6 +282,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_SingleUser_MultiClient_ClientASuccess() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
int[] users = Utils.prepareSingleUser(getDevice());
int initialUser = users[0];
@@ -318,6 +323,7 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
@Test
public void resumeOnReboot_SingleUser_MultiClient_ClientBSuccess() throws Exception {
assumeTrue("Device isn't at least S or has no lock screen", isSupportedSDevice());
+ assumeTrue("Device does not support file-based encryption", supportFileBasedEncryption());
int[] users = Utils.prepareSingleUser(getDevice());
int initialUser = users[0];
@@ -570,6 +576,10 @@ public class ResumeOnRebootHostTest extends BaseHostJUnit4Test {
return isAtleastS && getDevice().hasFeature(FEATURE_SECURE_LOCK_SCREEN);
}
+ private boolean supportFileBasedEncryption() throws Exception {
+ return "file".equals(getDevice().getProperty("ro.crypto.type"));
+ }
+
private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
public InstallMultiple() {
super(getDevice(), getBuild(), getAbi());
diff --git a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
index 12fbb3c4eea..aab1d9e6617 100644
--- a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
+++ b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
@@ -16,6 +16,7 @@
package android.appsecurity.cts.listeningports;
+import android.app.UiAutomation;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Process;
@@ -138,8 +139,15 @@ public class ListeningPortsTest extends AndroidTestCase {
}
private String uidToPackage(int uid) {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
PackageManager pm = this.getContext().getPackageManager();
- String[] packages = pm.getPackagesForUid(uid);
+ String[] packages;
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ packages = pm.getPackagesForUid(uid);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
if (packages == null) {
return "[unknown]";
}
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
index b3d1d1c4970..56d2e0723df 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -996,12 +996,7 @@ public class MediaStorageTest {
// to keep rolling forward if we can't find our grant button
final UiSelector grant = new UiSelector().textMatches("(?i)Allow");
if (isWatch()) {
- UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
- try {
- uiScrollable.scrollIntoView(grant);
- } catch (UiObjectNotFoundException e) {
- // Scrolling can fail if the UI is not scrollable
- }
+ scrollIntoView(grant);
}
final boolean grantExists = new UiObject(grant).waitForExists(timeout);
@@ -1016,8 +1011,11 @@ public class MediaStorageTest {
// Verify that we now have access
assertEquals(Activity.RESULT_OK, res.resultCode);
} else {
- // fine the Deny button
+ // find the Deny button
final UiSelector deny = new UiSelector().textMatches("(?i)Deny");
+ if (isWatch()) {
+ scrollIntoView(deny);
+ }
final boolean denyExists = new UiObject(deny).waitForExists(timeout);
assertThat(denyExists).isTrue();
@@ -1030,6 +1028,15 @@ public class MediaStorageTest {
}
}
+ private static void scrollIntoView(UiSelector selector) {
+ UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+ try {
+ uiScrollable.scrollIntoView(selector);
+ } catch (UiObjectNotFoundException e) {
+ // Scrolling can fail if the UI is not scrollable
+ }
+ }
+
private static Uri createDownload() throws IOException {
final String content = "<html><body>Content</body></html>";
final String displayName = "cts" + System.nanoTime();
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 94b83de6362..55e7dffc3fb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -36,9 +36,11 @@ import android.app.UiAutomation;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
@@ -46,7 +48,7 @@ import android.support.test.uiautomator.UiObject2;
import android.util.Log;
import com.android.compatibility.common.util.PollingCheck;
-
+import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.devicepolicy.PermissionBroadcastReceiver;
import com.android.cts.devicepolicy.PermissionUtils;
@@ -105,6 +107,11 @@ public class PermissionsTest extends BaseDeviceAdminTest {
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PERMISSION_RESULT));
mDevice = UiDevice.getInstance(getInstrumentation());
mUiAutomation = getInstrumentation().getUiAutomation();
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
+ "safety_center_qs_tile_component_setting_flags",
+ Integer.toString(PackageManager.DONT_KILL_APP), false);
+ });
}
@Override
diff --git a/hostsidetests/incident/AndroidTest.xml b/hostsidetests/incident/AndroidTest.xml
index 727277d3020..73be7b48824 100644
--- a/hostsidetests/incident/AndroidTest.xml
+++ b/hostsidetests/incident/AndroidTest.xml
@@ -20,9 +20,6 @@
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
<option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
- <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
- <option name="user-type" value="system" />
- </target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsIncidentHostTestCases.jar" />
</test>
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java
new file mode 100644
index 00000000000..223ea2229cf
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.Collections.singletonMap;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_261036568 extends NonRootSecurityTestCase {
+
+ private static final String TEST_PKG = "android.security.cts.BUG_261036568_test";
+
+ @Test
+ @AsbSecurityTest(cveBugId = 261036568)
+ public void testBug_261036568() {
+ ITestDevice device = null;
+ int newUser = -1;
+ try {
+ device = getDevice();
+ assumeTrue("Test requires multiple users", device.isMultiUserSupported());
+
+ newUser = device.createUser("CtsUser", /* guest */ true, /* ephemeral */ false);
+ assumeTrue("Unable to create test user", device.startUser(newUser, /* wait */ true));
+
+ installPackage("Bug-261036568-provider.apk", "--user " + newUser);
+ installPackage("Bug-261036568-test.apk");
+
+ Map<String, String> args = singletonMap("target_user", Integer.toString(newUser));
+ runDeviceTestsWithArgs(TEST_PKG, TEST_PKG + ".DeviceTest",
+ "testShareUnownedUriAsPreview", args);
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (newUser != -1) {
+ // Stop user 'CTSUser'
+ device.stopUser(newUser);
+
+ // Remove user 'CTSUser'
+ device.removeUser(newUser);
+ }
+ } catch (Exception e) {
+ CLog.e("failed to clean up guest user %d: %e", newUser, e);
+ }
+ }
+ }
+
+ private boolean runDeviceTestsWithArgs(String pkgName, String testClassName,
+ String testMethodName, Map<String, String> testArgs)
+ throws DeviceNotAvailableException {
+ final String testRunner = "androidx.test.runner.AndroidJUnitRunner";
+ final long defaultTestTimeoutMs = 60 * 1000L;
+ final long defaultMaxTimeoutToOutputMs = 60 * 1000L; // 1min
+ return runDeviceTests(getDevice(),
+ testRunner,
+ pkgName,
+ testClassName,
+ testMethodName,
+ /* userId */ null,
+ defaultTestTimeoutMs,
+ defaultMaxTimeoutToOutputMs,
+ /* maxInstrumentationTimeoutMillis */ 0L,
+ /* checkResults */ true,
+ /* isHiddenApiCheckDisabled */ false,
+ testArgs);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
index 57b9a86c191..010cce50ea8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
@@ -16,6 +16,9 @@
package android.security.cts;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
@@ -34,18 +37,25 @@ public class CVE_2021_0441 extends NonRootSecurityTestCase {
/**
* b/174495520
+ * Vulnerable Module : com.google.android.mediaprovider
+ * Is Play managed : Yes
*/
@AsbSecurityTest(cveBugId = 174495520)
@Test
- public void testPocCVE_2021_0441() throws Exception {
- ITestDevice device = getDevice();
- uninstallPackage(device, TEST_PKG);
-
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
-
- installPackage(TEST_APP);
- runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0441");
+ public void testPocCVE_2021_0441() {
+ try {
+ assumeFalse(moduleIsPlayManaged("com.google.android.mediaprovider"));
+ ITestDevice device = getDevice();
+ uninstallPackage(device, TEST_PKG);
+
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage(TEST_APP);
+ runDeviceTests(TEST_PKG, TEST_CLASS, "testCVE_2021_0441");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
index 90d8196c3f6..645f909f2f5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0963.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import static org.junit.Assume.assumeNoException;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -28,41 +28,39 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0963 extends StsExtraBusinessLogicHostTestBase {
- static final String TEST_PKG = "android.security.cts.CVE_2021_0963";
+public class CVE_2021_0963 extends NonRootSecurityTestCase {
- /**
- * b/199754277
- * Vulnerable app : KeyChain.apk
- * Vulnerable module : com.android.keychain
- * Is Play managed : No
- */
+ // b/199754277
+ // Vulnerable app : KeyChain.apk
+ // Vulnerable module : com.android.keychain
+ // Is Play managed : No
@AsbSecurityTest(cveBugId = 199754277)
@Test
public void testPocCVE_2021_0963() {
+ int userId = 0;
+ String component = null;
+ ITestDevice device = null;
try {
- ITestDevice device = getDevice();
+ // Install the application
+ installPackage("CVE-2021-0963.apk", "-t");
- /* Wake up the device */
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ // Set test-app as device owner.
+ final String testPkg = "android.security.cts.CVE_2021_0963";
+ component = testPkg + "/" + testPkg + ".PocDeviceAdminReceiver";
+ device = getDevice();
+ device.setDeviceOwner(component, userId);
- /* Install the application */
- installPackage("CVE-2021-0963.apk");
-
- /*
- * Set device as owner. After the test is completed, this change is reverted in the
- * DeviceTest.java's tearDown() method by calling clearDeviceOwnerApp() on an instance
- * of DevicePolicyManager.
- */
- AdbUtils.runCommandLine("dpm set-device-owner --user 0 '" + TEST_PKG + "/" + TEST_PKG
- + ".PocDeviceAdminReceiver" + "'", device);
-
- /* Run the device test "testOverlayButtonPresence" */
- runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+ // Run the device test "testOverlayButtonPresence"
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence");
} catch (Exception e) {
assumeNoException(e);
+ } finally {
+ try {
+ // Remove test-app as device owner.
+ device.removeAdmin(component, userId);
+ } catch (Exception e) {
+ // ignore
+ }
}
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java
new file mode 100644
index 00000000000..0568740ce20
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20360.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20360 extends NonRootSecurityTestCase {
+
+ // b/228314987
+ // Vulnerable apk : Settings.apk
+ // Vulnerable module : com.android.settings
+ // Is Play managed : No
+ @AsbSecurityTest(cveBugId = 228314987)
+ @Test
+ public void testPocCVE_2022_20360() {
+ final String testPkg = "android.security.cts.CVE_2022_20360";
+ ITestDevice device = null;
+ int currentUser = -1;
+ int newUser = -1;
+ try {
+ device = getDevice();
+
+ // Check if device supports nfc
+ assumeTrue("Device does not support nfc", device.hasFeature("android.hardware.nfc"));
+
+ // Get current user
+ currentUser = device.getCurrentUser();
+
+ // Create new guest user 'CTSUser' for test
+ newUser = device.createUser("CTSUser", true, false);
+
+ // Start new guest user 'CTSUser'
+ assumeTrue("Unable to create new guest user", device.startUser(newUser, true));
+
+ // Switch to new user 'CTSUser'
+ assumeTrue("Unable to switch to guest user", device.switchUser(newUser));
+
+ // Install test-app
+ installPackage("CVE-2022-20360.apk", "--user " + newUser);
+
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testSecureNfcPreferenceController");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (currentUser != -1) {
+ // Switch back to previous user
+ device.switchUser(currentUser);
+ }
+ if (newUser != -1) {
+ // Stop user 'CTSUser'
+ device.stopUser(newUser);
+
+ // Remove user 'CTSUser'
+ device.removeUser(newUser);
+ }
+ } catch (Exception e) {
+ // Ignore exception here
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
index 511cbd4ac45..e12c9253ab5 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20415.java
@@ -16,6 +16,7 @@
package android.security.cts;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNoException;
import android.platform.test.annotations.AsbSecurityTest;
@@ -37,6 +38,11 @@ public class CVE_2022_20415 extends NonRootSecurityTestCase {
@Test
public void testPocCVE_2022_20415() {
try {
+ // Test is not applicable for watch devices so skipping the test for watch devices
+ assumeFalse(
+ "Skipping the test for watch devices",
+ getDevice().hasFeature("android.hardware.type.watch"));
+
final String testPkg = "android.security.cts.CVE_2022_20415";
// Install the test-app
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20955.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20955.java
new file mode 100644
index 00000000000..96f2257ed15
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2023_20955.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2023_20955 extends NonRootSecurityTestCase {
+
+ // b/258653813
+ // Vulnerable app : Settings.apk
+ // Vulnerable package : com.android.settings
+ // Is Play Managed : No
+ @AsbSecurityTest(cveBugId = 240663194)
+ @Test
+ public void testPocCVE_2023_20955() {
+ int userId = -1;
+ ITestDevice device = null;
+ final String testPkg = "android.security.cts.CVE_2023_20955_test";
+ final String componentName = testPkg + "/.PocDeviceAdminReceiver";
+ try {
+ device = getDevice();
+
+ // Install the test app
+ installPackage("CVE-2023-20955-test.apk", "-t");
+
+ // Set test app as device owner
+ assumeTrue("Failed to set test app as device owner",
+ device.setDeviceOwner(componentName, 0));
+
+ // Create a new user
+ userId = device.createUser("CTSUser");
+ assumeTrue("Failed to create a user. ITestDevice.createUser() returned -1",
+ userId != -1);
+
+ // Install test helper app for all users
+ installPackage("CVE-2023-20955-test-helper.apk", "--user all");
+
+ // Run device test to check if App Info window allows uninstall for all users if
+ // DevicePolicyManager has restricted it.
+ runDeviceTests(testPkg, testPkg + ".DeviceTest",
+ "testAppInfoUninstallForAllUsersDisabled");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Remove user
+ device.removeUser(userId);
+
+ // Remove test app as device owner
+ device.removeAdmin(componentName, 0);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp
new file mode 100644
index 00000000000..d6d3022814e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "Bug-261036568-provider",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ asset_dirs: ["assets"],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml
new file mode 100644
index 00000000000..71e37a3431a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_261036568_provider">
+
+ <permission-tree android:name="com.android.cts"/>
+
+ <application
+ android:label="BUG-261036568-provider">>
+ <provider
+ android:name=".ImageProvider"
+ android:authorities="android.security.cts.BUG_261036568_provider"
+ android:enabled="true"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png
new file mode 100644
index 00000000000..8d17dab8f6f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java
new file mode 100644
index 00000000000..667a0c098e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_261036568_provider;
+
+import static android.os.Binder.getCallingUid;
+import static android.os.Binder.getCallingUserHandle;
+import static android.os.Process.myUid;
+import static android.os.Process.myUserHandle;
+import static android.provider.DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.provider.DocumentsContract;
+import android.provider.OpenableColumns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ImageProvider extends ContentProvider {
+
+ private final Set<String> accessedUris = new HashSet<>();
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
+ maybeRecordUriAccess(uri);
+ try {
+ return getContext().getAssets().openFd("x.png");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ AssetFileDescriptor fd = openAssetFile(uri, mode);
+ return fd == null ? null : fd.getParcelFileDescriptor();
+ }
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ Bundle result = new Bundle();
+ if (method.equals("verify")) {
+ result.putBoolean("passed", accessedUris.isEmpty());
+ result.putStringArrayList("accessed_uris", new ArrayList<>(accessedUris));
+ accessedUris.clear();
+ }
+ return result;
+ }
+
+
+ @Override
+ public String getType(Uri uri) {
+ return uri.getPath().endsWith(".png") ? "image/png" : "*/*";
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ MatrixCursor cursor = new MatrixCursor(new String[] {
+ OpenableColumns.DISPLAY_NAME,
+ DocumentsContract.Root.COLUMN_TITLE,
+ DocumentsContract.Document.COLUMN_FLAGS
+ });
+ cursor.addRow(new Object[] {
+ "DISPLAY_NAME",
+ "TITLE",
+ FLAG_SUPPORTS_THUMBNAIL
+ });
+ return cursor;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ private void maybeRecordUriAccess(Uri uri) {
+ UserHandle caller = getCallingUserHandle();
+ if (!myUserHandle().equals(caller)) {
+ accessedUris.add("uri=" + uri.toString()
+ + ", owner_uid=" + myUid()
+ + ", caller_uid=" + getCallingUid()
+ + " ('" + getCallingPackage() + "')");
+ }
+ }
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp
new file mode 100644
index 00000000000..f7103aaf99c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "Bug-261036568-test",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+ platform_apis: true,
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml
new file mode 100644
index 00000000000..c20ac2db0a1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_261036568_test"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.BUG_261036568_test"/>
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java
new file mode 100644
index 00000000000..ab09be5f42e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_261036568_test;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.ClipData;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final long WAIT_AND_ASSERT_FOUND_TIMEOUT_MS = 5000;
+ private static final long WAIT_FOR_IDLE_TIMEOUT_MS = 5000;
+ private static final long WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS = 2500;
+
+ private static final String PROVIDER_AUTHORITY = "android.security.cts.BUG_261036568_provider";
+ private static final Uri PROVIDER_AUTHORITY_URI = Uri.parse("content://" + PROVIDER_AUTHORITY);
+
+ private ContentProviderClient mClient;
+ private Uri mTargetImageUri;
+ private Uri mTargetAuthorityUri;
+ private Uri mTargetFileUri;
+
+ @Before
+ public void setUp() {
+ Instrumentation instrumentation = getInstrumentation();
+ Context context = instrumentation.getContext();
+
+ // Get the id of a test user created by host side test
+ Bundle args = InstrumentationRegistry.getArguments();
+ int targetUser = Integer.parseInt(args.getString("target_user", "-1"));
+ assumeTrue("Could not find target user", targetUser != -1);
+
+ mTargetAuthorityUri = withUserId(PROVIDER_AUTHORITY_URI, targetUser);
+ mTargetImageUri = withPath(mTargetAuthorityUri, "x.png");
+ mTargetFileUri = withPath(mTargetAuthorityUri, "x.pdf");
+ }
+
+ @Test
+ public void testShareUnownedUriAsPreview() {
+ // SEND, single image
+ openAndCloseSharesheet(createSendImageIntent(mTargetImageUri));
+ // SEND, text with thumbnail
+ openAndCloseSharesheet(createSendTextIntentWithPreview(mTargetImageUri));
+ // SEND_MULTIPLE, two images
+ openAndCloseSharesheet(createSendFileIntentWithPreview(mTargetImageUri, mTargetImageUri));
+ // SEND_MULTIPLE, mixed types
+ openAndCloseSharesheet(createSendFileIntentWithPreview(mTargetImageUri, mTargetFileUri));
+
+ verifyNoContentProviderAccess();
+ }
+
+ private void openAndCloseSharesheet(Intent target) {
+ Instrumentation instrumentation = getInstrumentation();
+ UiDevice device = UiDevice.getInstance(instrumentation);
+ Context context = instrumentation.getTargetContext();
+ Intent chooserIntent = Intent.createChooser(target, null);
+ chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ String chooserPackage = resolveChooserPackage(context);
+ context.startActivity(chooserIntent);
+ device.waitForIdle(WAIT_FOR_IDLE_TIMEOUT_MS);
+ if (waitForPackageVisible(device, chooserPackage)) {
+ device.pressBack();
+ assumeTrue(waitForPackageGone(device, chooserPackage));
+ }
+ }
+
+ private void verifyNoContentProviderAccess() {
+ Instrumentation instrumentation = getInstrumentation();
+ Context context = instrumentation.getContext();
+ UiAutomation automation = instrumentation.getUiAutomation();
+ ContentResolver resolver = context.getContentResolver();
+
+ // only used for verification to access the provider directly
+ automation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+
+ try (ContentProviderClient client =
+ resolver.acquireContentProviderClient(mTargetAuthorityUri)) {
+ assumeNotNull("Could not access '" + mTargetAuthorityUri, client);
+
+ Bundle result = client.call("verify", null, null);
+ assumeNotNull("Failed to fetch result from content provider", result);
+
+ boolean passed = result.getBoolean("passed");
+ ArrayList<String> accessedUris = result.getStringArrayList("accessed_uris");
+ assertTrue("Failed. Cross user URI reads detected: " + accessedUris, passed);
+ } catch (RemoteException e) {
+ assumeNoException("Caught exception verifying result: " + e, e);
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+ }
+
+ private Intent createSendImageIntent(Uri image) {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, image);
+ sendIntent.setType("image/png");
+ return sendIntent;
+ }
+
+ private Intent createSendTextIntentWithPreview(Uri image) {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_TITLE, "Preview Title");
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "Sharing Text");
+ sendIntent.setType("text/plain");
+ sendIntent.setClipData(
+ new ClipData(
+ "Clip Label",
+ new String[] {"image/png"},
+ new ClipData.Item(image)));
+ return sendIntent;
+ }
+
+ private Intent createSendFileIntentWithPreview(Uri... uris) {
+ Intent sendIntent = new Intent();
+ if (uris.length > 1) {
+ sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
+ sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,
+ new ArrayList<>(Arrays.asList(uris)));
+ } else if (uris.length == 1) {
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, uris[0]);
+ }
+ sendIntent.setType("application/pdf");
+ return sendIntent;
+ }
+
+ private String resolveChooserPackage(Context context) {
+ PackageManager pm = context.getPackageManager();
+ Intent shareIntent = Intent.createChooser(new Intent(), null);
+ ResolveInfo chooser = pm.resolveActivity(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ assertNotNull(chooser);
+ assertNotNull(chooser.activityInfo);
+ return chooser.activityInfo.packageName;
+ }
+
+ /**
+ * Same as waitAndAssertFound but searching the entire device UI.
+ */
+ private boolean waitForPackageVisible(UiDevice device, String pkg) {
+ return device.wait(
+ Until.findObject(By.pkg(pkg).depth(0)),
+ WAIT_AND_ASSERT_FOUND_TIMEOUT_MS
+ ) != null;
+ }
+
+ /**
+ * Same as waitAndAssertNotFound() but searching the entire device UI.
+ */
+ private boolean waitForPackageGone(UiDevice device, String pkg) {
+ return device.wait(Until.gone(By.pkg(pkg)), WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS);
+ }
+
+ private static Uri withUserId(Uri uri, int userId) {
+ Uri.Builder builder = uri.buildUpon();
+ builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
+ return builder.build();
+ }
+
+ private static Uri withPath(Uri uri, String path) {
+ return uri.buildUpon().appendPath(path).build();
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
index ea39e68b2be..2a307910faa 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/Android.bp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,5 +35,5 @@ android_test_helper_app {
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
],
- platform_apis: true,
+ platform_apis: true, // required for using RemoteCallback
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
index ae0d4160fcb..dec0ae40059 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2022 The Android Open Source Project
+ Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts.CVE_2021_0963">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <application>
+ <application android:testOnly="true">
<activity android:name=".PocActivity"
android:exported="true">
<intent-filter>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_pkey b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_pkey
new file mode 100644
index 00000000000..3a071135dfb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_pkey
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_usercert b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_usercert
new file mode 100644
index 00000000000..4665a94043a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/raw/cve_2021_0963_usercert
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
index 6a14b4a8240..18ccaba3381 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/integers.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2022 The Android Open Source Project
+ Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
index 1da84fe3711..e6915d6df3e 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2022 The Android Open Source Project
+ Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,25 +16,32 @@
-->
<resources>
- <string name="actionKeychainActivity">com.android.keychain.CHOOSER</string>
- <string name="activityNotFoundMsg">The activity with intent was not found : </string>
- <string name="activityNotStartedException">Unable to start the activity with intent : </string>
+ <string name="action">com.android.keychain.CHOOSER</string>
<string name="alias">Client</string>
- <string name="callbackKey">callback</string>
- <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
- <string name="certType">X.509</string>
- <string name="dumpsysActivity">dumpsys activity %1$s</string>
- <string name="dumpsysActivityNotStartedException">Could not execute dumpsys activity command
- </string>
- <string name="errorMessage">Device is vulnerable to b/199754277 hence any app with
- "SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
- <string name="keyType">RSA</string>
- <string name="mResumedTrue">mResumed=true</string>
- <string name="messageKey">message</string>
- <string name="overlayButtonText">OverlayButton</string>
- <string name="overlayServiceNotStartedException">Unable to start the overlay service</string>
- <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
- <string name="statusKey">status</string>
- <string name="vulActivityNotRunningError">The activity %1$s is not currently running
- on the device</string>
+ <string name="callback">callback</string>
+ <string name="cmdAdbHome">input keyevent KEYCODE_HOME</string>
+ <string name="cmdDumpsysActivityByActivity">dumpsys activity %1$s</string>
+ <string name="cmdDumpsysActivityByPkg">dumpsys activity -p %1$s activities</string>
+ <string name="exceptionActivityNotFound">The activity with intent was not found : </string>
+ <string name="exceptionActivityNotStart">Unable to start the activity with intent : </string>
+ <string name="exceptionCanNotDrawOverlays">The application cannot draw overlays</string>
+ <string name="exceptionOverlayUiNotVisible">Overlay UI did not appear on the screen</string>
+ <string name="exceptionServiceNotStart">Unable to start the overlay service</string>
+ <string name="exceptionVulActivityNotResume">The activity %1$s is not currently resumed on the
+ device</string>
+ <string name="exceptionVulUiNotVisible">UI of vulnerable activity %1$s is not visible</string>
+ <string name="failMsg">Device is vulnerable to b/199754277 !! Any app with SYSTEM_ALERT_WINDOW
+ can overlay the %1$s screen</string>
+ <string name="flagActivityResumed">mResumed=true</string>
+ <string name="flagActivityVisible">mVisible=true</string>
+ <string name="message">message</string>
+ <string name="pKey">cve_2021_0963_pkey</string>
+ <string name="rawResOpenError">Could not open the raw resource %1$s</string>
+ <string name="status">status</string>
+ <string name="strSplitRegex"><![CDATA[((?<=mVisible=(true|false)))]]></string>
+ <string name="streamReadError">Could not read from stream of the raw resource %1$s</string>
+ <string name="txtOverlayBtn">CVE_2021_0963_button</string>
+ <string name="typeCert">X.509</string>
+ <string name="typeKey">RSA</string>
+ <string name="userCert">cve_2021_0963_usercert</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
index a826e80f531..ed5352d7c0f 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/res/xml/device_policies.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2022 The Android Open Source Project
+ Copyright 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,6 +16,5 @@
-->
<device-admin>
- <uses-policies>
- </uses-policies>
+ <uses-policies />
</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
index 3d1c0df2131..209bdf06306 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/DeviceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.Certificate;
@@ -56,256 +59,31 @@ import java.util.regex.Pattern;
public class DeviceTest {
private DevicePolicyManager mDevicePolicyManager;
private ComponentName mComponentName;
- Context mContext;
-
- /**
- * Generated from above and converted with:
- *
- * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- private static final byte[] PRIVATE_KEY =
- new byte[] {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x76, (byte) 0x02,
- (byte) 0x01, (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
- (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
- (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04,
- (byte) 0x82, (byte) 0x02, (byte) 0x60, (byte) 0x30, (byte) 0x82, (byte) 0x02,
- (byte) 0x5c, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81,
- (byte) 0x81, (byte) 0x00, (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8,
- (byte) 0xc4, (byte) 0x44, (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1,
- (byte) 0xb9, (byte) 0x1b, (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f,
- (byte) 0x06, (byte) 0xe7, (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8,
- (byte) 0xaa, (byte) 0x0a, (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b,
- (byte) 0xad, (byte) 0xfe, (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d,
- (byte) 0xc9, (byte) 0xf5, (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1,
- (byte) 0xcc, (byte) 0x3f, (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67,
- (byte) 0x6a, (byte) 0xe8, (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a,
- (byte) 0x53, (byte) 0xd9, (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90,
- (byte) 0xbb, (byte) 0x95, (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32,
- (byte) 0xce, (byte) 0xf8, (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19,
- (byte) 0x91, (byte) 0x29, (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1,
- (byte) 0xcb, (byte) 0xa7, (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a,
- (byte) 0x0c, (byte) 0x07, (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d,
- (byte) 0x08, (byte) 0xf4, (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66,
- (byte) 0x28, (byte) 0xcb, (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f,
- (byte) 0x7e, (byte) 0x83, (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83,
- (byte) 0x2d, (byte) 0xa0, (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68,
- (byte) 0x47, (byte) 0x31, (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e,
- (byte) 0x12, (byte) 0x1b, (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8,
- (byte) 0x84, (byte) 0x5f, (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03,
- (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80,
- (byte) 0x24, (byte) 0x95, (byte) 0xb8, (byte) 0xe1, (byte) 0xf4, (byte) 0x7b,
- (byte) 0xbc, (byte) 0x0c, (byte) 0x6d, (byte) 0x4d, (byte) 0x01, (byte) 0xe2,
- (byte) 0x42, (byte) 0xe2, (byte) 0x9a, (byte) 0xe4, (byte) 0xab, (byte) 0xe2,
- (byte) 0x9a, (byte) 0x8c, (byte) 0xd5, (byte) 0x93, (byte) 0xe8, (byte) 0x43,
- (byte) 0x77, (byte) 0x85, (byte) 0xfd, (byte) 0xf3, (byte) 0xd8, (byte) 0xd6,
- (byte) 0xe9, (byte) 0x02, (byte) 0xf3, (byte) 0xbf, (byte) 0x82, (byte) 0x65,
- (byte) 0xc3, (byte) 0x7c, (byte) 0x96, (byte) 0x09, (byte) 0x04, (byte) 0x16,
- (byte) 0x1d, (byte) 0x03, (byte) 0x3d, (byte) 0x82, (byte) 0xb8, (byte) 0xdc,
- (byte) 0xbb, (byte) 0xd6, (byte) 0xbf, (byte) 0x2a, (byte) 0x52, (byte) 0x83,
- (byte) 0x76, (byte) 0x5b, (byte) 0xae, (byte) 0x59, (byte) 0xf6, (byte) 0xee,
- (byte) 0x84, (byte) 0x44, (byte) 0x4a, (byte) 0xa7, (byte) 0x25, (byte) 0x50,
- (byte) 0x89, (byte) 0x63, (byte) 0x43, (byte) 0x0b, (byte) 0xc8, (byte) 0xd5,
- (byte) 0x17, (byte) 0x9d, (byte) 0x8b, (byte) 0x62, (byte) 0xd5, (byte) 0xf1,
- (byte) 0xde, (byte) 0x45, (byte) 0xe6, (byte) 0x35, (byte) 0x10, (byte) 0xba,
- (byte) 0x58, (byte) 0x18, (byte) 0x44, (byte) 0xc1, (byte) 0x6d, (byte) 0xb6,
- (byte) 0x1d, (byte) 0x2f, (byte) 0x53, (byte) 0xb6, (byte) 0x5a, (byte) 0xf1,
- (byte) 0x66, (byte) 0xbc, (byte) 0x0e, (byte) 0x63, (byte) 0xa7, (byte) 0x0f,
- (byte) 0x81, (byte) 0x4b, (byte) 0x07, (byte) 0x31, (byte) 0xa5, (byte) 0x70,
- (byte) 0xec, (byte) 0x30, (byte) 0x57, (byte) 0xc4, (byte) 0x14, (byte) 0xb2,
- (byte) 0x8b, (byte) 0x6f, (byte) 0x26, (byte) 0x7e, (byte) 0x55, (byte) 0x60,
- (byte) 0x63, (byte) 0x7d, (byte) 0x90, (byte) 0xd7, (byte) 0x5f, (byte) 0xef,
- (byte) 0x7d, (byte) 0xc1, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xfe,
- (byte) 0x92, (byte) 0xa9, (byte) 0xf1, (byte) 0x29, (byte) 0x1e, (byte) 0xd4,
- (byte) 0x72, (byte) 0xd3, (byte) 0x3f, (byte) 0x9d, (byte) 0xd6, (byte) 0x3d,
- (byte) 0xe9, (byte) 0xcf, (byte) 0x3e, (byte) 0x06, (byte) 0xdc, (byte) 0x65,
- (byte) 0x8f, (byte) 0xc0, (byte) 0x81, (byte) 0xc2, (byte) 0x66, (byte) 0xc1,
- (byte) 0x5c, (byte) 0x2c, (byte) 0xfa, (byte) 0x08, (byte) 0x65, (byte) 0xb6,
- (byte) 0x47, (byte) 0xc5, (byte) 0x14, (byte) 0x8d, (byte) 0x69, (byte) 0xe9,
- (byte) 0xaf, (byte) 0x42, (byte) 0x02, (byte) 0x53, (byte) 0x04, (byte) 0x63,
- (byte) 0x47, (byte) 0xaf, (byte) 0xcc, (byte) 0xae, (byte) 0x08, (byte) 0x31,
- (byte) 0xba, (byte) 0xea, (byte) 0x85, (byte) 0xda, (byte) 0xd6, (byte) 0xb2,
- (byte) 0xe7, (byte) 0x4c, (byte) 0xda, (byte) 0xad, (byte) 0x52, (byte) 0x76,
- (byte) 0x48, (byte) 0x16, (byte) 0xeb, (byte) 0x02, (byte) 0x41, (byte) 0x00,
- (byte) 0xef, (byte) 0xc4, (byte) 0x7d, (byte) 0x69, (byte) 0x7b, (byte) 0xcb,
- (byte) 0xcb, (byte) 0xf7, (byte) 0x00, (byte) 0x2d, (byte) 0x05, (byte) 0x3c,
- (byte) 0xe4, (byte) 0xfd, (byte) 0x5c, (byte) 0xea, (byte) 0xcf, (byte) 0x40,
- (byte) 0x84, (byte) 0x10, (byte) 0xf1, (byte) 0xc0, (byte) 0xaf, (byte) 0xc7,
- (byte) 0xc8, (byte) 0x51, (byte) 0xac, (byte) 0x18, (byte) 0x25, (byte) 0x63,
- (byte) 0x75, (byte) 0xc7, (byte) 0x0e, (byte) 0xa9, (byte) 0xed, (byte) 0x9c,
- (byte) 0x78, (byte) 0x08, (byte) 0x28, (byte) 0x1d, (byte) 0x9e, (byte) 0xfa,
- (byte) 0x17, (byte) 0x0f, (byte) 0x7a, (byte) 0x6a, (byte) 0x78, (byte) 0x63,
- (byte) 0x6e, (byte) 0xb3, (byte) 0x6b, (byte) 0xd6, (byte) 0x43, (byte) 0x4b,
- (byte) 0x58, (byte) 0xb8, (byte) 0x77, (byte) 0x10, (byte) 0x07, (byte) 0x70,
- (byte) 0xa6, (byte) 0xa9, (byte) 0xae, (byte) 0x0d, (byte) 0x02, (byte) 0x41,
- (byte) 0x00, (byte) 0x92, (byte) 0x4c, (byte) 0x79, (byte) 0x0b, (byte) 0x95,
- (byte) 0xc5, (byte) 0x18, (byte) 0xf4, (byte) 0x90, (byte) 0x40, (byte) 0x8c,
- (byte) 0x15, (byte) 0x96, (byte) 0x69, (byte) 0x2a, (byte) 0xe7, (byte) 0x8b,
- (byte) 0x8b, (byte) 0xd7, (byte) 0x76, (byte) 0x00, (byte) 0x7c, (byte) 0xd1,
- (byte) 0xda, (byte) 0xb9, (byte) 0x9e, (byte) 0x9e, (byte) 0x5e, (byte) 0x66,
- (byte) 0xbb, (byte) 0x05, (byte) 0x41, (byte) 0x43, (byte) 0x9a, (byte) 0x67,
- (byte) 0x16, (byte) 0x89, (byte) 0xec, (byte) 0x65, (byte) 0x33, (byte) 0xee,
- (byte) 0xbf, (byte) 0xa3, (byte) 0xca, (byte) 0x8b, (byte) 0xd6, (byte) 0x45,
- (byte) 0xe1, (byte) 0x81, (byte) 0xaa, (byte) 0xd8, (byte) 0xa2, (byte) 0x6a,
- (byte) 0x3c, (byte) 0x5e, (byte) 0x7e, (byte) 0x1c, (byte) 0xa5, (byte) 0xc3,
- (byte) 0x5b, (byte) 0x93, (byte) 0x8c, (byte) 0x24, (byte) 0x57, (byte) 0x02,
- (byte) 0x40, (byte) 0x0a, (byte) 0x6d, (byte) 0x3f, (byte) 0x0e, (byte) 0xf1,
- (byte) 0x45, (byte) 0x41, (byte) 0x8f, (byte) 0x72, (byte) 0x40, (byte) 0x82,
- (byte) 0xf3, (byte) 0xcc, (byte) 0xf9, (byte) 0x7f, (byte) 0xaa, (byte) 0xee,
- (byte) 0x6c, (byte) 0x5d, (byte) 0xd1, (byte) 0xe6, (byte) 0xd1, (byte) 0x7c,
- (byte) 0x53, (byte) 0x71, (byte) 0xd0, (byte) 0xab, (byte) 0x6d, (byte) 0x39,
- (byte) 0x63, (byte) 0x03, (byte) 0xe2, (byte) 0x2e, (byte) 0x2f, (byte) 0x11,
- (byte) 0x98, (byte) 0x36, (byte) 0x58, (byte) 0x14, (byte) 0x76, (byte) 0x85,
- (byte) 0x4d, (byte) 0x56, (byte) 0xe7, (byte) 0x63, (byte) 0x69, (byte) 0x71,
- (byte) 0xe6, (byte) 0xd1, (byte) 0x0f, (byte) 0x98, (byte) 0x66, (byte) 0xee,
- (byte) 0xf2, (byte) 0x3d, (byte) 0xdf, (byte) 0x77, (byte) 0xbe, (byte) 0x08,
- (byte) 0xb4, (byte) 0xcb, (byte) 0x6a, (byte) 0xa1, (byte) 0x99, (byte) 0x02,
- (byte) 0x40, (byte) 0x52, (byte) 0x01, (byte) 0xde, (byte) 0x62, (byte) 0xc2,
- (byte) 0x25, (byte) 0xbf, (byte) 0x5d, (byte) 0x77, (byte) 0xe4, (byte) 0x6b,
- (byte) 0xb6, (byte) 0xd7, (byte) 0x8f, (byte) 0x89, (byte) 0x2c, (byte) 0xe6,
- (byte) 0x8d, (byte) 0xe5, (byte) 0xad, (byte) 0x39, (byte) 0x17, (byte) 0x54,
- (byte) 0x2b, (byte) 0x35, (byte) 0x53, (byte) 0xd1, (byte) 0xa1, (byte) 0xef,
- (byte) 0x48, (byte) 0xbc, (byte) 0x95, (byte) 0x48, (byte) 0xcf, (byte) 0x62,
- (byte) 0xf4, (byte) 0x33, (byte) 0xcf, (byte) 0x37, (byte) 0x78, (byte) 0xeb,
- (byte) 0x17, (byte) 0xb4, (byte) 0x0b, (byte) 0x83, (byte) 0x4f, (byte) 0xb6,
- (byte) 0xab, (byte) 0x7d, (byte) 0x67, (byte) 0x3e, (byte) 0x4e, (byte) 0x44,
- (byte) 0x4a, (byte) 0x55, (byte) 0x2e, (byte) 0x34, (byte) 0x12, (byte) 0x0b,
- (byte) 0x59, (byte) 0xb3, (byte) 0xb1, (byte) 0x1e, (byte) 0x3d};
-
-
- /**
- * Generated from above and converted with:
- *
- * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
- */
- private static final byte[] USER_CERT =
- {(byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xd8, (byte) 0x30, (byte) 0x82,
- (byte) 0x01, (byte) 0xc0, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
- (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
- (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x0b, (byte) 0x05,
- (byte) 0x00, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
- (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
- (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
- (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
- (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
- (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x06,
- (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
- (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x32,
- (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x30, (byte) 0x37,
- (byte) 0x32, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x5a, (byte) 0x17,
- (byte) 0x0d, (byte) 0x33, (byte) 0x32, (byte) 0x30, (byte) 0x33, (byte) 0x32,
- (byte) 0x32, (byte) 0x30, (byte) 0x37, (byte) 0x32, (byte) 0x30, (byte) 0x31,
- (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x33, (byte) 0x31, (byte) 0x0b,
- (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
- (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31,
- (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
- (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f,
- (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61,
- (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x0f, (byte) 0x30, (byte) 0x0d,
- (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c,
- (byte) 0x06, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c,
- (byte) 0x65, (byte) 0x30, (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d,
- (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
- (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05,
- (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30,
- (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00,
- (byte) 0xee, (byte) 0x6e, (byte) 0x51, (byte) 0xa8, (byte) 0xc4, (byte) 0x44,
- (byte) 0xd9, (byte) 0xb7, (byte) 0x53, (byte) 0xf1, (byte) 0xb9, (byte) 0x1b,
- (byte) 0x9d, (byte) 0x8d, (byte) 0x7c, (byte) 0x9f, (byte) 0x06, (byte) 0xe7,
- (byte) 0xed, (byte) 0xa8, (byte) 0x05, (byte) 0xb8, (byte) 0xaa, (byte) 0x0a,
- (byte) 0x2d, (byte) 0x74, (byte) 0x05, (byte) 0x8b, (byte) 0xad, (byte) 0xfe,
- (byte) 0xd3, (byte) 0x3e, (byte) 0x08, (byte) 0x9d, (byte) 0xc9, (byte) 0xf5,
- (byte) 0xf7, (byte) 0x81, (byte) 0x90, (byte) 0xf1, (byte) 0xcc, (byte) 0x3f,
- (byte) 0x91, (byte) 0xda, (byte) 0xcb, (byte) 0x67, (byte) 0x6a, (byte) 0xe8,
- (byte) 0x4a, (byte) 0xa0, (byte) 0xc3, (byte) 0x8a, (byte) 0x53, (byte) 0xd9,
- (byte) 0xf0, (byte) 0x17, (byte) 0xbe, (byte) 0x90, (byte) 0xbb, (byte) 0x95,
- (byte) 0x29, (byte) 0x01, (byte) 0xce, (byte) 0x32, (byte) 0xce, (byte) 0xf8,
- (byte) 0x02, (byte) 0xfe, (byte) 0xe8, (byte) 0x19, (byte) 0x91, (byte) 0x29,
- (byte) 0x46, (byte) 0xf7, (byte) 0x67, (byte) 0xd1, (byte) 0xcb, (byte) 0xa7,
- (byte) 0x20, (byte) 0x8b, (byte) 0x85, (byte) 0x8a, (byte) 0x0c, (byte) 0x07,
- (byte) 0xf8, (byte) 0xfe, (byte) 0xf4, (byte) 0x5d, (byte) 0x08, (byte) 0xf4,
- (byte) 0x63, (byte) 0x4a, (byte) 0x69, (byte) 0x66, (byte) 0x28, (byte) 0xcb,
- (byte) 0x0d, (byte) 0x1c, (byte) 0x7f, (byte) 0x7f, (byte) 0x7e, (byte) 0x83,
- (byte) 0x49, (byte) 0x66, (byte) 0x6c, (byte) 0x83, (byte) 0x2d, (byte) 0xa0,
- (byte) 0x51, (byte) 0xf6, (byte) 0x14, (byte) 0x68, (byte) 0x47, (byte) 0x31,
- (byte) 0x72, (byte) 0x4d, (byte) 0xe9, (byte) 0x1e, (byte) 0x12, (byte) 0x1b,
- (byte) 0xd0, (byte) 0xe6, (byte) 0x21, (byte) 0xd8, (byte) 0x84, (byte) 0x5f,
- (byte) 0xe3, (byte) 0xef, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00,
- (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30,
- (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
- (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c,
- (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
- (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04,
- (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65,
- (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47,
- (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74,
- (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72,
- (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
- (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03,
- (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04,
- (byte) 0x14, (byte) 0xee, (byte) 0xec, (byte) 0x08, (byte) 0xcc, (byte) 0xdd,
- (byte) 0xa3, (byte) 0x29, (byte) 0x6e, (byte) 0x2b, (byte) 0x78, (byte) 0x23,
- (byte) 0xb3, (byte) 0xf0, (byte) 0xb8, (byte) 0x9d, (byte) 0x53, (byte) 0x41,
- (byte) 0x2e, (byte) 0x3c, (byte) 0x61, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
- (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18,
- (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x86, (byte) 0xdb,
- (byte) 0xa5, (byte) 0x5e, (byte) 0x0e, (byte) 0x03, (byte) 0xbc, (byte) 0xe4,
- (byte) 0xc1, (byte) 0xc8, (byte) 0xf3, (byte) 0xed, (byte) 0x24, (byte) 0x48,
- (byte) 0xb1, (byte) 0x37, (byte) 0x3a, (byte) 0x52, (byte) 0x10, (byte) 0x57,
- (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
- (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
- (byte) 0x0b, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x82, (byte) 0x01,
- (byte) 0x01, (byte) 0x00, (byte) 0x15, (byte) 0x5a, (byte) 0x5c, (byte) 0x08,
- (byte) 0xe4, (byte) 0x0e, (byte) 0x28, (byte) 0x4c, (byte) 0xa9, (byte) 0x0e,
- (byte) 0x35, (byte) 0xbe, (byte) 0xe3, (byte) 0xd5, (byte) 0xd1, (byte) 0xb4,
- (byte) 0x47, (byte) 0x87, (byte) 0x63, (byte) 0xd2, (byte) 0x5e, (byte) 0x7e,
- (byte) 0xf6, (byte) 0xd8, (byte) 0xce, (byte) 0xdf, (byte) 0x10, (byte) 0x15,
- (byte) 0x61, (byte) 0xc4, (byte) 0x9a, (byte) 0xf1, (byte) 0xba, (byte) 0x33,
- (byte) 0xf2, (byte) 0xc2, (byte) 0x01, (byte) 0x95, (byte) 0xa7, (byte) 0x74,
- (byte) 0x97, (byte) 0xc1, (byte) 0x43, (byte) 0x68, (byte) 0x92, (byte) 0xbe,
- (byte) 0x9a, (byte) 0x6f, (byte) 0x38, (byte) 0xcb, (byte) 0xa0, (byte) 0xcf,
- (byte) 0x1e, (byte) 0x5b, (byte) 0x03, (byte) 0xde, (byte) 0x45, (byte) 0x6d,
- (byte) 0xea, (byte) 0xf0, (byte) 0x46, (byte) 0x4d, (byte) 0xb6, (byte) 0x4b,
- (byte) 0x88, (byte) 0xc7, (byte) 0xb8, (byte) 0xe3, (byte) 0x9f, (byte) 0x58,
- (byte) 0x8b, (byte) 0x2d, (byte) 0xbf, (byte) 0x4b, (byte) 0x3f, (byte) 0x54,
- (byte) 0x2d, (byte) 0xa8, (byte) 0x27, (byte) 0x72, (byte) 0x5e, (byte) 0x36,
- (byte) 0x67, (byte) 0x5c, (byte) 0x6e, (byte) 0x9a, (byte) 0x67, (byte) 0x73,
- (byte) 0x44, (byte) 0xaf, (byte) 0x46, (byte) 0x7f, (byte) 0xd6, (byte) 0x2b,
- (byte) 0x9d, (byte) 0x28, (byte) 0xb1, (byte) 0xc4, (byte) 0xc4, (byte) 0x72,
- (byte) 0x3d, (byte) 0x6d, (byte) 0x7d, (byte) 0x28, (byte) 0x40, (byte) 0x62,
- (byte) 0x40, (byte) 0x21, (byte) 0x52, (byte) 0xb5, (byte) 0x0b, (byte) 0xf3,
- (byte) 0xcc, (byte) 0x36, (byte) 0x03, (byte) 0x10, (byte) 0x19, (byte) 0xe3,
- (byte) 0xc2, (byte) 0xfe, (byte) 0xe9, (byte) 0x08, (byte) 0x0d, (byte) 0xd4,
- (byte) 0x8b, (byte) 0x12, (byte) 0xd6, (byte) 0x3d, (byte) 0xc5, (byte) 0xb8,
- (byte) 0x8c, (byte) 0xbd, (byte) 0xa5, (byte) 0xcd, (byte) 0xb3, (byte) 0xe4,
- (byte) 0xd1, (byte) 0xd8, (byte) 0x4c, (byte) 0x32, (byte) 0x44, (byte) 0x3f,
- (byte) 0x63, (byte) 0x32, (byte) 0x09, (byte) 0xdb, (byte) 0x8b, (byte) 0x7b,
- (byte) 0x30, (byte) 0x58, (byte) 0xc7, (byte) 0xcf, (byte) 0xc3, (byte) 0x44,
- (byte) 0xd9, (byte) 0xff, (byte) 0x63, (byte) 0x91, (byte) 0x74, (byte) 0xd8,
- (byte) 0x62, (byte) 0x2b, (byte) 0x52, (byte) 0xc8, (byte) 0x82, (byte) 0x9f,
- (byte) 0xeb, (byte) 0x22, (byte) 0x5c, (byte) 0xa2, (byte) 0x26, (byte) 0xfe,
- (byte) 0x04, (byte) 0x31, (byte) 0x53, (byte) 0x09, (byte) 0xa7, (byte) 0x23,
- (byte) 0xe3, (byte) 0x0f, (byte) 0xf8, (byte) 0xe9, (byte) 0x99, (byte) 0xad,
- (byte) 0x4b, (byte) 0x23, (byte) 0x07, (byte) 0xfb, (byte) 0xfa, (byte) 0xc3,
- (byte) 0x55, (byte) 0x59, (byte) 0xdb, (byte) 0x6b, (byte) 0x71, (byte) 0xdf,
- (byte) 0x25, (byte) 0x0f, (byte) 0xaa, (byte) 0xa2, (byte) 0xfa, (byte) 0x28,
- (byte) 0x49, (byte) 0x65, (byte) 0x7e, (byte) 0x0b, (byte) 0x74, (byte) 0x30,
- (byte) 0xd9, (byte) 0x9a, (byte) 0xfe, (byte) 0x2c, (byte) 0x8c, (byte) 0x67,
- (byte) 0x50, (byte) 0x0c, (byte) 0x6d, (byte) 0x4c, (byte) 0xba, (byte) 0x34,
- (byte) 0x3b, (byte) 0x0d, (byte) 0x16, (byte) 0x45, (byte) 0x63, (byte) 0x73,
- (byte) 0xc2, (byte) 0x9f, (byte) 0xb4, (byte) 0xdd, (byte) 0x6f, (byte) 0xde,
- (byte) 0x9d, (byte) 0x71, (byte) 0xbf, (byte) 0x8d, (byte) 0x1b, (byte) 0x79,
- (byte) 0xa0, (byte) 0x0a, (byte) 0x66, (byte) 0x7e, (byte) 0x56, (byte) 0x83,
- (byte) 0x8f, (byte) 0x3f, (byte) 0x7d, (byte) 0x93, (byte) 0xf6, (byte) 0xc9,
- (byte) 0x42, (byte) 0xfc, (byte) 0xc5, (byte) 0xf2, (byte) 0x49, (byte) 0xec};
+ private Context mContext;
+ private UiDevice mDevice;
+ private Resources mResources;
+
+ private byte[] getByteArrayFromRawRes(int resId, String resName) throws IOException {
+ byte[] byteArray = null;
+ try (InputStream inStream = mResources.openRawResource(resId);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); ) {
+ assumeTrue(mContext.getString(R.string.rawResOpenError, resName), inStream != null);
+ byteArray = new byte[1024];
+ int nRead = inStream.read(byteArray, 0, byteArray.length);
+ assumeTrue(mContext.getString(R.string.streamReadError, resName), nRead > 0);
+ outStream.write(byteArray, 0, nRead);
+ }
+ return byteArray;
+ }
@After
public void tearDown() {
try {
+ // Go to home screen
+ mDevice.executeShellCommand(mContext.getString(R.string.cmdAdbHome));
+
+ // Remove key pair added by the test as part of cleanup
mDevicePolicyManager.removeKeyPair(mComponentName, mContext.getString(R.string.alias));
- mDevicePolicyManager.clearDeviceOwnerApp(mContext.getPackageName());
} catch (Exception e) {
// ignore all exceptions as the test is already complete
}
@@ -314,85 +92,146 @@ public class DeviceTest {
@Test
public void testOverlayButtonPresence() {
try {
- /* Install key pair required to launch KeyChainActivity dialog */
+ // Create the byte arrays from raw resources of private key and user certificate
+ // respectively.
mContext = getInstrumentation().getContext();
- Resources resources = mContext.getResources();
- KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.keyType));
- PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(PRIVATE_KEY));
+ mResources = mContext.getResources();
+ byte[] privateKeyByteArray =
+ getByteArrayFromRawRes(
+ R.raw.cve_2021_0963_pkey, mContext.getString(R.string.pKey));
+ byte[] userCertByteArray =
+ getByteArrayFromRawRes(
+ R.raw.cve_2021_0963_usercert, mContext.getString(R.string.userCert));
+
+ // Install key pair required to launch KeyChainActivity dialog
+ KeyFactory kf = KeyFactory.getInstance(mContext.getString(R.string.typeKey));
+ PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyByteArray));
CertificateFactory cf =
- CertificateFactory.getInstance(mContext.getString(R.string.certType));
- Certificate cert = cf.generateCertificate(new ByteArrayInputStream(USER_CERT));
+ CertificateFactory.getInstance(mContext.getString(R.string.typeCert));
+ Certificate cert = cf.generateCertificate(new ByteArrayInputStream(userCertByteArray));
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
- mComponentName = new ComponentName(PocDeviceAdminReceiver.class.getPackage().getName(),
- PocDeviceAdminReceiver.class.getName());
- assumeTrue(mDevicePolicyManager.installKeyPair(mComponentName, privKey, cert,
- mContext.getString(R.string.alias)));
+ mComponentName =
+ new ComponentName(
+ PocDeviceAdminReceiver.class.getPackage().getName(),
+ PocDeviceAdminReceiver.class.getName());
+ assumeTrue(
+ mDevicePolicyManager.installKeyPair(
+ mComponentName, privKey, cert, mContext.getString(R.string.alias)));
- /* Start the overlay service */
+ // Start the overlay service
Intent intent = new Intent(mContext, PocService.class);
- assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+ assumeTrue(
+ mContext.getString(R.string.exceptionCanNotDrawOverlays),
Settings.canDrawOverlays(mContext));
CompletableFuture<PocStatus> callbackReturn = new CompletableFuture<>();
- RemoteCallback cb = new RemoteCallback((Bundle result) -> {
- PocStatus pocStatus =
- new PocStatus(result.getInt(mContext.getString(R.string.statusKey)),
- result.getString(mContext.getString(R.string.messageKey)));
- callbackReturn.complete(pocStatus);
- });
- intent.putExtra(mContext.getString(R.string.callbackKey), cb);
+ RemoteCallback cb =
+ new RemoteCallback(
+ (Bundle result) -> {
+ PocStatus pocStatus =
+ new PocStatus(
+ result.getInt(mContext.getString(R.string.status)),
+ result.getString(
+ mContext.getString(R.string.message)));
+ callbackReturn.complete(pocStatus);
+ });
+ intent.putExtra(mContext.getString(R.string.callback), cb);
mContext.startService(intent);
- PocStatus result = callbackReturn.get(resources.getInteger(R.integer.timeoutMs),
- TimeUnit.MILLISECONDS);
- assumeTrue(result.getErrorMessage(),
- result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
-
- /* Wait for the overlay window */
- Pattern overlayTextPattern = Pattern.compile(
- mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
- UiDevice device = UiDevice.getInstance(getInstrumentation());
- assumeTrue(mContext.getString(R.string.overlayUiScreenError),
- device.wait(Until.hasObject(By.text(overlayTextPattern)),
- mContext.getResources().getInteger(R.integer.timeoutMs)));
+ PocStatus result =
+ callbackReturn.get(
+ mResources.getInteger(R.integer.timeoutMs), TimeUnit.MILLISECONDS);
+ assumeTrue(
+ result.getErrorMessage(),
+ result.getStatusCode() != mResources.getInteger(R.integer.assumptionFailure));
+
+ // Wait for the overlay window
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ Pattern overlayTextPattern =
+ Pattern.compile(
+ mContext.getString(R.string.txtOverlayBtn), Pattern.CASE_INSENSITIVE);
+ assumeTrue(
+ mContext.getString(R.string.exceptionOverlayUiNotVisible),
+ mDevice.wait(
+ Until.hasObject(By.text(overlayTextPattern)),
+ mResources.getInteger(R.integer.timeoutMs)));
- /* Start PocActivity which starts the vulnerable activity */
+ // Start PocActivity which in turn starts the vulnerable activity
intent = new Intent(mContext, PocActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
CompletableFuture<PocStatus> pocActivityReturn = new CompletableFuture<>();
- RemoteCallback pocActivityCb = new RemoteCallback((Bundle pocActivityResult) -> {
- PocStatus pocStatus = new PocStatus(
- pocActivityResult.getInt(mContext.getString(R.string.statusKey)),
- pocActivityResult.getString(mContext.getString(R.string.messageKey)));
- pocActivityReturn.complete(pocStatus);
- });
- intent.putExtra(mContext.getString(R.string.callbackKey), pocActivityCb);
+ RemoteCallback pocActivityCb =
+ new RemoteCallback(
+ (Bundle pocActivityResult) -> {
+ PocStatus pocStatus =
+ new PocStatus(
+ pocActivityResult.getInt(
+ mContext.getString(R.string.status)),
+ pocActivityResult.getString(
+ mContext.getString(R.string.message)));
+ pocActivityReturn.complete(pocStatus);
+ });
+ intent.putExtra(mContext.getString(R.string.callback), pocActivityCb);
mContext.startActivity(intent);
- result = pocActivityReturn.get(resources.getInteger(R.integer.timeoutMs),
- TimeUnit.MILLISECONDS);
- assumeTrue(result.getErrorMessage(),
- result.getStatusCode() != resources.getInteger(R.integer.assumptionFailure));
-
- /* Get the vulnerable activity name by using an alternative intent */
- Intent vulIntent = new Intent(mContext.getString(R.string.actionKeychainActivity));
- ResolveInfo ri = mContext.getPackageManager().resolveActivity(vulIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
+ result =
+ pocActivityReturn.get(
+ mResources.getInteger(R.integer.timeoutMs), TimeUnit.MILLISECONDS);
+ assumeTrue(
+ result.getErrorMessage(),
+ result.getStatusCode() != mResources.getInteger(R.integer.assumptionFailure));
+
+ // Get the vulnerable activity name by using an alternative intent
+ Intent vulIntent = new Intent(mContext.getString(R.string.action));
+ ResolveInfo ri =
+ mContext.getPackageManager()
+ .resolveActivity(vulIntent, PackageManager.MATCH_DEFAULT_ONLY);
String vulnerableActivityName = ri.activityInfo.name;
-
- /* Wait until the object of launcher activity is gone */
- boolean overlayDisallowed = device.wait(Until.gone(By.pkg(mContext.getPackageName())),
- mContext.getResources().getInteger(R.integer.timeoutMs));
-
- /* Check if the currently running activity is the vulnerable activity */
- String activityDump = "";
- activityDump = device.executeShellCommand(
- mContext.getString(R.string.dumpsysActivity, vulnerableActivityName));
- Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
- Pattern.CASE_INSENSITIVE);
+ String vulnerablePkgName = ri.activityInfo.packageName;
+
+ // Wait until the object of launcher activity is gone
+ boolean overlayDisallowed =
+ mDevice.wait(
+ Until.gone(By.pkg(mContext.getPackageName())),
+ mResources.getInteger(R.integer.timeoutMs));
+
+ // Check if the currently resumed activity is the vulnerable activity
+ String activityDump =
+ mDevice.executeShellCommand(
+ mContext.getString(
+ R.string.cmdDumpsysActivityByActivity, vulnerableActivityName));
+ Pattern activityPattern =
+ Pattern.compile(
+ mContext.getString(R.string.flagActivityResumed),
+ Pattern.CASE_INSENSITIVE);
assumeTrue(
- mContext.getString(R.string.vulActivityNotRunningError, vulnerableActivityName),
+ mContext.getString(
+ R.string.exceptionVulActivityNotResume, vulnerableActivityName),
activityPattern.matcher(activityDump).find());
- /* Failing the test as fix is not present */
- assertTrue(mContext.getString(R.string.errorMessage, vulnerableActivityName),
+ // Check if vulnerable activity's UI is visible
+ String vulPkgDump =
+ mDevice.executeShellCommand(
+ mContext.getString(
+ R.string.cmdDumpsysActivityByPkg, vulnerablePkgName));
+ boolean isVisible = false;
+ for (String vulPkgDumpElement :
+ vulPkgDump.split(mContext.getString(R.string.strSplitRegex))) {
+ if (vulPkgDumpElement
+ .toLowerCase()
+ .contains(vulnerableActivityName.toLowerCase())) {
+ if (vulPkgDumpElement.contains(
+ mContext.getString(R.string.flagActivityVisible))) {
+ isVisible = true;
+ break;
+ }
+ }
+ }
+ assumeTrue(
+ mContext.getString(R.string.exceptionVulUiNotVisible, vulnerableActivityName),
+ isVisible);
+
+ // On vulnerable device, vulnerable activity will be overlaid so 'overlayDisallowed'
+ // will be set to true so the test fails, else it passes.
+ assertTrue(
+ mContext.getString(R.string.failMsg, vulnerableActivityName),
overlayDisallowed);
} catch (Exception e) {
assumeNoException(e);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
index ac8ea15c6e0..bcf98e116fa 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,13 +27,19 @@ import androidx.annotation.Nullable;
public class PocActivity extends Activity {
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onResume() {
try {
- super.onCreate(savedInstanceState);
- KeyChainAliasCallback callback = new KeyChainAliasCallback() {
- @Override
- public void alias(@Nullable String alias) {}
- };
+ super.onResume();
+
+ // Waiting briefly for the PocActivity window transition animation to complete.
+ Thread.sleep(500);
+
+ // Launching the vulnerable activity KeyChainActivity
+ KeyChainAliasCallback callback =
+ new KeyChainAliasCallback() {
+ @Override
+ public void alias(@Nullable String alias) {}
+ };
KeyChain.choosePrivateKeyAlias(this, callback, null, null, null, -1, null);
sendTestResult(getResources().getInteger(R.integer.noException), "");
} catch (Exception e) {
@@ -44,10 +50,10 @@ public class PocActivity extends Activity {
void sendTestResult(int status, String message) {
try {
RemoteCallback cb =
- (RemoteCallback) getIntent().getExtras().get(getString(R.string.callbackKey));
+ (RemoteCallback) getIntent().getExtras().get(getString(R.string.callback));
Bundle res = new Bundle();
- res.putString(getString(R.string.messageKey), message);
- res.putInt(getString(R.string.statusKey), status);
+ res.putString(getString(R.string.message), message);
+ res.putInt(getString(R.string.status), status);
cb.sendResult(res);
} catch (Exception e) {
// ignore all exceptions
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
index 5592323071b..b8ef104dca4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocDeviceAdminReceiver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,5 +18,4 @@ package android.security.cts.CVE_2021_0963;
import android.app.admin.DeviceAdminReceiver;
-public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
-}
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
index b83e8247d54..c78d7d4a656 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -55,8 +55,8 @@ public class PocService extends Service {
mWindowManager = getSystemService(WindowManager.class);
mLayoutParams = new LayoutParams();
mLayoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
- mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL |
- LayoutParams.FLAG_NOT_FOCUSABLE;
+ mLayoutParams.flags =
+ LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.format = PixelFormat.OPAQUE;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.width = getScreenWidth();
@@ -65,7 +65,7 @@ public class PocService extends Service {
mLayoutParams.y = getScreenHeight() / 2;
Context context = getApplicationContext();
mButton = new Button(context);
- mButton.setText(context.getString(R.string.overlayButtonText));
+ mButton.setText(context.getString(R.string.txtOverlayBtn));
mWindowManager.addView(mButton, mLayoutParams);
sendTestResult(getResources().getInteger(R.integer.noException), "");
} catch (Exception e) {
@@ -87,10 +87,10 @@ public class PocService extends Service {
void sendTestResult(int status, String message) {
try {
RemoteCallback cb =
- (RemoteCallback) mIntent.getExtras().get(getString(R.string.callbackKey));
+ (RemoteCallback) mIntent.getExtras().get(getString(R.string.callback));
Bundle res = new Bundle();
- res.putString(getString(R.string.messageKey), message);
- res.putInt(getString(R.string.statusKey), status);
+ res.putString(getString(R.string.message), message);
+ res.putInt(getString(R.string.status), status);
cb.sendResult(res);
} catch (Exception e) {
// ignore exception here
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
index de67f0ff104..7e6c63d7c73 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0963/src/android/security/cts/CVE_2021_0963/PocStatus.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp
new file mode 100644
index 00000000000..d9f8554c32d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/Android.bp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20360",
+ defaults: [
+ "cts_support_defaults"
+ ],
+ srcs: [
+ "src/**/*.java"
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml
new file mode 100644
index 00000000000..9e2361a9750
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20360">
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20360" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml
new file mode 100644
index 00000000000..9476f7af344
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="defaultSettingsPkg">com.android.settings</string>
+ <string name="disableSecureNfcFailed">Disabling secure NFC failed</string>
+ <string name="key">key</string>
+ <string name="msgDeviceLocked">Device is in sleep or locked mode</string>
+ <string name="msgTestFail"> Device is vulnerable to b/228314987!! Secure nfc can be disabled in
+ guest user via SettingsSlice</string>
+ <string name="secureNfcPreferenceControllerClassName">.nfc.SecureNfcPreferenceController
+ </string>
+ <string name="setCheckedMethod">setChecked</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java
new file mode 100644
index 00000000000..9e73804e1b7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20360/src/android/security/cts/CVE_2022_20360/DeviceTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20360;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcManager;
+import android.os.PowerManager;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+
+ @Test
+ public void testSecureNfcPreferenceController() {
+ boolean secureNfcEnabled = false;
+ NfcAdapter nfcAdapter = null;
+ UiAutomation uiAutomation = null;
+ try {
+ Context context = getApplicationContext();
+ NfcManager nfcManager = context.getSystemService(NfcManager.class);
+ nfcAdapter = nfcManager.getDefaultAdapter();
+ uiAutomation = getInstrumentation().getUiAutomation();
+
+ // Secure NFC APIs require device to be unlocked hence check if device is unlocked
+ PowerManager powerManager = context.getSystemService(PowerManager.class);
+ KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+ assumeTrue(context.getString(R.string.msgDeviceLocked),
+ powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
+
+
+ // Save secure NFC state(enabled/disabled) and disable secure NFC for test
+ secureNfcEnabled = nfcAdapter.isSecureNfcEnabled();
+ if (secureNfcEnabled) {
+ nfcAdapter.enableSecureNfc(false);
+ }
+ assumeFalse(context.getString(R.string.disableSecureNfcFailed),
+ nfcAdapter.isSecureNfcEnabled());
+
+ // Retrieve settings package name dynamically
+ Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+ ComponentName settingsComponent =
+ settingsIntent.resolveActivity(context.getPackageManager());
+ String settingsPkgName = settingsComponent != null ? settingsComponent.getPackageName()
+ : context.getString(R.string.defaultSettingsPkg);
+
+ // Get vulnerable method 'setChecked' using reflection
+ Context settingsContext = context.createPackageContext(settingsPkgName,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ ClassLoader settingsClassLoader = settingsContext.getClassLoader();
+ Class<?> targetClass = settingsClassLoader.loadClass(settingsPkgName
+ + context.getString(R.string.secureNfcPreferenceControllerClassName));
+ Constructor<?> targetClassCstr =
+ targetClass.getConstructor(Context.class, String.class);
+ Object targetClassobject =
+ targetClassCstr.newInstance(context, context.getString(R.string.key));
+ Method setCheckedMethod = targetClass
+ .getDeclaredMethod(context.getString(R.string.setCheckedMethod), boolean.class);
+ setCheckedMethod.setAccessible(true);
+
+ // Check if current user is guest user
+ uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.CREATE_USERS);
+ UserManager userManager = context.getSystemService(UserManager.class);
+ assumeTrue(userManager.isGuestUser());
+
+ // Invoke vulnerable method 'setChecked'
+ boolean retVal = (boolean) setCheckedMethod.invoke(targetClassobject, true);
+ assertFalse(context.getString(R.string.msgTestFail), retVal);
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Disable secure NFC if it was disabled before the test
+ if (!secureNfcEnabled) {
+ nfcAdapter.enableSecureNfc(false);
+ }
+ } catch (Exception ignored) {
+ // Ignore any exception here
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/Android.bp
new file mode 100644
index 00000000000..e856574ef9c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2023-20955-test",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "test-app/src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ resource_dirs: [
+ "test-app/res",
+ ],
+ manifest: "test-app/AndroidManifest.xml",
+ sdk_version: "current",
+}
+
+android_test_helper_app {
+ name: "CVE-2023-20955-test-helper",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ manifest: "test-helper-app/AndroidManifest.xml",
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/AndroidManifest.xml
new file mode 100644
index 00000000000..2d74f5492fc
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2023_20955_test">
+ <application android:testOnly="true">
+ <receiver android:name=".PocDeviceAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_policies" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2023_20955_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/values/strings.xml
new file mode 100644
index 00000000000..194436bd2b9
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="failMsg">Vulnerable to b/258653813 !!</string>
+ <string name="msgNotFoundTxt">Did not find an object with selector %1$s on the screen</string>
+ <string name="msgSetUserRestrictionFailed">Failed to set user restriction DISALLOW_APPS_CONTROL
+ </string>
+ <string name="patternMoreOptions">.*more options.*</string>
+ <string name="patternUninstall">.*uninstall.*</string>
+ <string name="patternUninstallAllUsers">.*uninstall for all users.*</string>
+ <string name="pkgNameHelper">android.security.cts.CVE_2023_20955_test_helper</string>
+ <string name="pkgNameInstaller">com.android.packageinstaller</string>
+ <string name="uriScheme">package</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/xml/device_policies.xml
new file mode 100644
index 00000000000..ed5352d7c0f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/res/xml/device_policies.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<device-admin>
+ <uses-policies />
+</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/DeviceTest.java
new file mode 100644
index 00000000000..8b769040010
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/DeviceTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20955_test;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.widget.ImageButton;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final int TIMEOUT_MS = 5000;
+ private Context mContext;
+ private UiDevice mDevice;
+
+ private void waitAndClick(BySelector selector) {
+ assumeTrue(mContext.getString(R.string.msgNotFoundTxt, selector.toString()),
+ mDevice.wait(Until.hasObject(selector), TIMEOUT_MS));
+ mDevice.findObject(selector).click();
+ }
+
+ @Test
+ public void testAppInfoUninstallForAllUsersDisabled() {
+ try {
+ mContext = getInstrumentation().getTargetContext();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+
+ // Restrict current user to disallow controlling apps
+ ComponentName deviceAdminComponent =
+ new ComponentName(mContext, PocDeviceAdminReceiver.class);
+ DevicePolicyManager policyManager = null;
+ policyManager = mContext.getSystemService(DevicePolicyManager.class);
+ policyManager.addUserRestriction(deviceAdminComponent,
+ UserManager.DISALLOW_APPS_CONTROL);
+
+ // Waiting for user restriction to be added
+ boolean disallowAppsControlVal =
+ (boolean) policyManager.getUserRestrictions(deviceAdminComponent)
+ .getBoolean(UserManager.DISALLOW_APPS_CONTROL);
+ while (!disallowAppsControlVal && System.currentTimeMillis() < TIMEOUT_MS) {
+ disallowAppsControlVal = policyManager.getUserRestrictions(deviceAdminComponent)
+ .getBoolean(UserManager.DISALLOW_APPS_CONTROL);
+ Thread.sleep(100);
+ }
+ assumeTrue(mContext.getString(R.string.msgSetUserRestrictionFailed),
+ disallowAppsControlVal);
+
+ // Launching "application info" window for test helper app
+ Uri pkgUri = Uri.fromParts(mContext.getString(R.string.uriScheme),
+ mContext.getString(R.string.pkgNameHelper), null);
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, pkgUri);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+
+ // Wait for the application info window and click on 3 dots with:
+ // content description = "More options"
+ Pattern descPattern = Pattern.compile(mContext.getString(R.string.patternMoreOptions),
+ Pattern.CASE_INSENSITIVE);
+ waitAndClick(By.clazz(ImageButton.class).desc(descPattern));
+
+ // Wait for a menu to appear. When it appears, click on the text "Uninstall for all
+ // users".
+ Pattern textPattern =
+ Pattern.compile(mContext.getString(R.string.patternUninstallAllUsers),
+ Pattern.CASE_INSENSITIVE);
+ waitAndClick(By.text(textPattern));
+
+ // Retrieve the package name of installer app
+ Intent packageInstallerIntent = new Intent(Intent.ACTION_DELETE, pkgUri);
+ ComponentName componentName =
+ packageInstallerIntent.resolveActivity(mContext.getPackageManager());
+ String pkgNameInstaller = mContext.getString(R.string.pkgNameInstaller);
+ if (componentName != null && componentName.getPackageName() != null) {
+ pkgNameInstaller = componentName.getPackageName();
+ }
+
+ // Wait for UI with package = "com.android.packageinstaller" (AOSP), text containing
+ // "uninstall". If found, it indicates vulnerable behaviour and anyone can uninstall
+ // app for all users despite the user restrictions.
+ textPattern = Pattern.compile(mContext.getString(R.string.patternUninstall),
+ Pattern.CASE_INSENSITIVE);
+ assertFalse(mContext.getString(R.string.failMsg), mDevice
+ .wait(Until.hasObject(By.pkg(pkgNameInstaller).text(textPattern)), TIMEOUT_MS));
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Go to the home screen
+ mDevice.pressHome();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/PocDeviceAdminReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/PocDeviceAdminReceiver.java
new file mode 100644
index 00000000000..7141a402e65
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-app/src/android/security/cts/CVE_2023_20955_test/PocDeviceAdminReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2023_20955_test;
+
+import android.app.admin.DeviceAdminReceiver;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-helper-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-helper-app/AndroidManifest.xml
new file mode 100644
index 00000000000..73420e4b366
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2023-20955/test-helper-app/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest package="android.security.cts.CVE_2023_20955_test_helper">
+ <application />
+</manifest>
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index 3b81acb26d8..86df388d725 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -116,7 +116,7 @@ public class TestUsbTest extends DeviceTestCase implements IAbiReceiver, IBuildR
/**
* Check if adb serial number, USB serial number, ro.serialno, and android.os.Build.SERIAL
- * all matches and meets the format requirement [a-zA-Z0-9]{6,20}
+ * all matches and meets the format requirement [a-zA-Z0-9\\._\\-,]+
*/
@AppModeInstant(reason = "only instant apps fail when reading serial")
public void testInstantAppsCannotReadSerial() throws Exception {
@@ -127,7 +127,7 @@ public class TestUsbTest extends DeviceTestCase implements IAbiReceiver, IBuildR
/**
* Check if adb serial number, USB serial number, ro.serialno, and android.os.Build.SERIAL
- * all matches and meets the format requirement [a-zA-Z0-9]{6,20}
+ * all matches and meets the format requirement [a-zA-Z0-9\\._\\-,]+
*/
@AppModeFull(reason = "serial can not be read by instant apps")
public void testUsbSerialReadOnDeviceMatches() throws Exception {
@@ -148,7 +148,7 @@ public class TestUsbTest extends DeviceTestCase implements IAbiReceiver, IBuildR
CommandResult result = RunUtil.getDefault().runTimedCmd(15000, "lsusb", "-v");
assertEquals("lsusb -v failed", result.getStatus(), CommandStatus.SUCCESS);
String lsusbOutput = result.getStdout();
- Pattern pattern = Pattern.compile("^\\s+iSerial\\s+\\d+\\s+([a-zA-Z0-9]{6,20})",
+ Pattern pattern = Pattern.compile("^\\s+iSerial\\s+\\d+\\s+([a-zA-Z0-9\\._\\-,]+)",
Pattern.MULTILINE);
Matcher matcher = pattern.matcher(lsusbOutput);
String usbSerial = "";
@@ -166,7 +166,7 @@ public class TestUsbTest extends DeviceTestCase implements IAbiReceiver, IBuildR
runTestOnDevice("logSerial");
String logs = mDevice.executeAdbCommand(
"logcat", "-v", "brief", "-d", "CtsUsbSerialTest:W", "*:S");
- pattern = Pattern.compile("^.*CtsUsbSerialTest\\(.*\\):\\s+([a-zA-Z0-9]{6,20})",
+ pattern = Pattern.compile("^.*CtsUsbSerialTest\\(.*\\):\\s+([a-zA-Z0-9\\._\\-,]+)",
Pattern.MULTILINE);
matcher = pattern.matcher(logs);
String buildSerial = "";
diff --git a/libs/webkit-shared/src/android/webkit/cts/ExceptionWrapper.java b/libs/webkit-shared/src/android/webkit/cts/ExceptionWrapper.java
new file mode 100644
index 00000000000..a4aca088280
--- /dev/null
+++ b/libs/webkit-shared/src/android/webkit/cts/ExceptionWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit.cts;
+
+import android.os.RemoteException;
+
+/**
+ * Binder only handles a few exceptions. Runtime exceptions are silently ignored and any errors
+ * thrown will result in crashing the entire process and meaning no further tests will pass. We deal
+ * with this in a bit of a sneaky sneaky way and wrap any throwables in one of the supported
+ * exception types (IllegalStateException seems fairly representative of if the host app environment
+ * is broken), and then catch that and re-expose it in the SharedSdkWebServer where we strip that
+ * exception type out to avoid confusion.
+ *
+ * <p>The wrap/unwrap methods from this class should be used on either side of IPC calls by the
+ * IHostAppInvoker and IWebServer.
+ *
+ * <p>This allows JUnit to deal with any major broken program flows gracefully instead of moving on
+ * or crashing the rest of the tests.
+ *
+ * <p>It should be noted that binder parcel will take the cause and stringify the stack trace so the
+ * type information of these exceptions is lost in the journey. This means that the test code will
+ * not be able to react to these exception types. This is already a limitation of communicating
+ * through binder.
+ */
+class ExceptionWrapper {
+ public static <T> T wrap(WrappedTypedCall<T> c) {
+ try {
+ return c.wrap();
+ } catch (Throwable e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static void wrap(WrappedVoidCall r) {
+ wrap(() -> {
+ r.wrap();
+ return null;
+ });
+ }
+
+ public static <T> T unwrap(UnwrappedTypedCall<T> c) {
+ try {
+ return c.unwrap();
+ } catch (RemoteException e) {
+ // We are handling the remote exception separately from the IllegalStateException
+ // because this is happening binder proxy side so we would like to preserve the
+ // exception information.
+ // We still wrap this in a runtime exception so that the WebServer tests don't need to
+ // throw inside the Webkit utils run on main sync method as that would mean those
+ // functions would all have to return null (it would turn them into callables instead of
+ // runnables).
+ throw new RuntimeException(e);
+ } catch (IllegalStateException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ public static void unwrap(UnwrappedVoidCall c) {
+ unwrap(() -> {
+ c.unwrap();
+ return null;
+ });
+ }
+
+ interface WrappedTypedCall<T> {
+ T wrap() throws Exception;
+ }
+
+ interface WrappedVoidCall {
+ void wrap() throws Exception;
+ }
+
+ interface UnwrappedTypedCall<T> {
+ T unwrap() throws RemoteException;
+ }
+
+ interface UnwrappedVoidCall {
+ void unwrap() throws RemoteException;
+ }
+}
diff --git a/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java b/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java
index c3ceaf8c84a..ac3fb6dcef8 100644
--- a/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java
+++ b/libs/webkit-shared/src/android/webkit/cts/SharedSdkWebServer.java
@@ -16,7 +16,6 @@
package android.webkit.cts;
-import android.os.RemoteException;
import androidx.annotation.Nullable;
@@ -38,31 +37,25 @@ public final class SharedSdkWebServer {
}
/** Starts the web server using the provided parameters}. */
- public void start(@SslMode int sslMode, @Nullable byte[] acceptedIssuerDer,
- int keyResId, int certResId) {
- try {
+ public void start(
+ @SslMode int sslMode, @Nullable byte[] acceptedIssuerDer, int keyResId, int certResId) {
+ ExceptionWrapper.unwrap(() -> {
mWebServer.start(sslMode, acceptedIssuerDer, keyResId, certResId);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Shuts down the web server if it was started. */
public void shutdown() {
- try {
+ ExceptionWrapper.unwrap(() -> {
mWebServer.shutdown();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Resets all request state stored. */
public void resetRequestState() {
- try {
+ ExceptionWrapper.unwrap(() -> {
mWebServer.resetRequestState();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/**
@@ -71,162 +64,128 @@ public final class SharedSdkWebServer {
*/
public String setResponse(
String path, String responseString, List<HttpHeader> responseHeaders) {
- // We can't send a null value as a list
- // so default to an empty list if null was provided.
- if (responseHeaders == null) {
- responseHeaders = Collections.emptyList();
- }
- try {
- return mWebServer.setResponse(path, responseString, responseHeaders);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ return ExceptionWrapper.unwrap(() -> {
+ // We can't send a null value as a list
+ // so default the responseHeaders to an empty list if null was provided.
+ return mWebServer.setResponse(
+ path,
+ responseString,
+ responseHeaders == null ? Collections.emptyList() : responseHeaders);
+ });
}
/** Return the absolute URL that refers to a path. */
public String getAbsoluteUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getAbsoluteUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns a url that will contain the user agent in the header and in the body. */
public String getUserAgentUrl() {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getUserAgentUrl();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Get a delayed assert url for an asset path. */
public String getDelayedAssetUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getDelayedAssetUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Get a url that will redirect for a path. */
public String getRedirectingAssetUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getRedirectingAssetUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Get the full url for an asset. */
public String getAssetUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getAssetUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Get the full auth url for an asset. */
public String getAuthAssetUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getAuthAssetUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Get a binary url. */
public String getBinaryUrl(String mimeType, int contentLength) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getBinaryUrl(mimeType, contentLength);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns the url to the app cache. */
public String getAppCacheUrl() {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getAppCacheUrl();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns how many requests have been made. */
public int getRequestCount() {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getRequestCount();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns the request count for a particular path */
public int getRequestCount(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getRequestCountWithPath(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Verify if a resource was requested. */
public boolean wasResourceRequested(String url) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.wasResourceRequested(url);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Retrieve the last request to be made on a url. */
public HttpRequest getLastRequest(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getLastRequest(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Retrieve the last request for an asset path to be made on a url. */
public HttpRequest getLastAssetRequest(String url) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getLastAssetRequest(url);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns a url that will contain the path as a cookie. */
public String getCookieUrl(String path) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getCookieUrl(path);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/**
- * Returns a URL that attempts to set the cookie
- * "key=value" with the given list of attributes when fetched.
- */
+ * Returns a URL that attempts to set the cookie "key=value" with the given list of attributes
+ * when fetched.
+ */
public String getSetCookieUrl(String path, String key, String value, String attributes) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getSetCookieUrl(path, key, value, attributes);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns a URL for a page with a script tag where src equals the URL passed in. */
public String getLinkedScriptUrl(String path, String url) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mWebServer.getLinkedScriptUrl(path, url);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
}
diff --git a/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java b/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java
index eb43397fad6..d777c624678 100644
--- a/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java
+++ b/libs/webkit-shared/src/android/webkit/cts/SharedWebViewTestEnvironment.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.*;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.Context;
-import android.os.RemoteException;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
import android.view.MotionEvent;
@@ -37,7 +36,6 @@ import androidx.test.InstrumentationRegistry;
import org.apache.http.util.EncodingUtils;
import java.io.ByteArrayInputStream;
-import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
@@ -90,66 +88,50 @@ public final class SharedWebViewTestEnvironment {
* Use this method instead of EncodingUtils.getBytes.
*/
public byte[] getEncodingBytes(String data, String charset) {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return mHostAppInvoker.getEncodingBytes(data, charset);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Invokes waitForIdleSync on the {@link Instrumentation} in the activity. */
public void waitForIdleSync() {
- try {
+ ExceptionWrapper.unwrap(() -> {
mHostAppInvoker.waitForIdleSync();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Invokes sendKeyDownUpSync on the {@link Instrumentation} in the activity. */
public void sendKeyDownUpSync(int keyCode) {
- try {
+ ExceptionWrapper.unwrap(() -> {
mHostAppInvoker.sendKeyDownUpSync(keyCode);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Invokes sendPointerSync on the {@link Instrumentation} in the activity. */
public void sendPointerSync(MotionEvent event) {
- try {
+ ExceptionWrapper.unwrap(() -> {
mHostAppInvoker.sendPointerSync(event);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
/** Returns a web server that can be used for web based testing. */
public SharedSdkWebServer getWebServer() {
- try {
+ return ExceptionWrapper.unwrap(() -> {
return new SharedSdkWebServer(mHostAppInvoker.getWebServer());
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ });
}
- /** Returns a web server that has been started and can be used
- * for web based testing. */
+ /** Returns a web server that has been started and can be used for web based testing. */
public SharedSdkWebServer getSetupWebServer(@SslMode int sslMode) {
return getSetupWebServer(sslMode, null, 0, 0);
}
- /** Returns a web server that has been started and can be used
- * for web based testing. */
- public SharedSdkWebServer getSetupWebServer(@SslMode int sslMode,
- @Nullable byte[] acceptedIssuerDer, int keyResId, int certResId) {
- try {
- SharedSdkWebServer webServer = getWebServer();
- webServer.start(sslMode, acceptedIssuerDer, keyResId, certResId);
- return webServer;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ /** Returns a web server that has been started and can be used for web based testing. */
+ public SharedSdkWebServer getSetupWebServer(
+ @SslMode int sslMode, @Nullable byte[] acceptedIssuerDer, int keyResId, int certResId) {
+ SharedSdkWebServer webServer = getWebServer();
+ webServer.start(sslMode, acceptedIssuerDer, keyResId, certResId);
+ return webServer;
}
/**
@@ -227,171 +209,211 @@ public final class SharedWebViewTestEnvironment {
private UiAutomation mUiAutomation;
public void waitForIdleSync() {
- mInstrumentation.waitForIdleSync();
+ ExceptionWrapper.wrap(() -> {
+ mInstrumentation.waitForIdleSync();
+ });
}
public void sendKeyDownUpSync(int keyCode) {
- mInstrumentation.sendKeyDownUpSync(keyCode);
+ ExceptionWrapper.wrap(() -> {
+ mInstrumentation.sendKeyDownUpSync(keyCode);
+ });
}
public void sendPointerSync(MotionEvent event) {
- if (allowUiAutomation) {
- sendPointerSyncWithUiAutomation(event);
- } else {
- sendPointerSyncWithInstrumentation(event);
- }
+ ExceptionWrapper.wrap(() -> {
+ if (allowUiAutomation) {
+ sendPointerSyncWithUiAutomation(event);
+ } else {
+ sendPointerSyncWithInstrumentation(event);
+ }
+ });
}
public byte[] getEncodingBytes(String data, String charset) {
- return EncodingUtils.getBytes(data, charset);
+ return ExceptionWrapper.wrap(() -> {
+ return EncodingUtils.getBytes(data, charset);
+ });
}
public IWebServer getWebServer() {
return new IWebServer.Stub() {
private CtsTestServer mWebServer;
- public void start(@SslMode int sslMode, @Nullable byte[] acceptedIssuerDer,
- int keyResId, int certResId) {
- assertNull(mWebServer);
- final X509Certificate[] acceptedIssuerCerts;
- if (acceptedIssuerDer != null) {
- try {
+ public void start(
+ @SslMode int sslMode,
+ @Nullable byte[] acceptedIssuerDer,
+ int keyResId,
+ int certResId) {
+ ExceptionWrapper.wrap(() -> {
+ assertNull(mWebServer);
+ final X509Certificate[] acceptedIssuerCerts;
+ if (acceptedIssuerDer != null) {
CertificateFactory certFactory =
CertificateFactory.getInstance("X.509");
- acceptedIssuerCerts =
- new X509Certificate[] {
- (X509Certificate)
- certFactory.generateCertificate(
- new ByteArrayInputStream(
- acceptedIssuerDer))
- };
- } catch (CertificateException e) {
- // Throw manually, because compiler does not understand that fail()
- // does not return.
- throw new AssertionError(
- "Failed to create certificate chain: " + e.toString());
+ acceptedIssuerCerts = new X509Certificate[] {
+ (X509Certificate) certFactory.generateCertificate(
+ new ByteArrayInputStream(acceptedIssuerDer))
+ };
+ } else {
+ acceptedIssuerCerts = null;
}
- } else {
- acceptedIssuerCerts = null;
- }
- try {
- X509TrustManager trustManager = new CtsTestServer.CtsTrustManager() {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return acceptedIssuerCerts;
- }
- };
- mWebServer = new CtsTestServer(applicationContext, sslMode,
- trustManager, keyResId, certResId);
- } catch (Exception e) {
- fail(" Failed to launch CtsTestServer: " + e);
- }
+ X509TrustManager trustManager =
+ new CtsTestServer.CtsTrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return acceptedIssuerCerts;
+ }
+ };
+ mWebServer = new CtsTestServer(
+ applicationContext, sslMode, trustManager, keyResId, certResId);
+ });
}
public void shutdown() {
if (mWebServer == null) {
return;
}
- ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
- ThreadPolicy tmpPolicy =
- new ThreadPolicy.Builder(oldPolicy).permitNetwork().build();
- StrictMode.setThreadPolicy(tmpPolicy);
- mWebServer.shutdown();
- mWebServer = null;
- StrictMode.setThreadPolicy(oldPolicy);
+ ExceptionWrapper.wrap(() -> {
+ ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ ThreadPolicy tmpPolicy =
+ new ThreadPolicy.Builder(oldPolicy)
+ .permitNetwork()
+ .build();
+ StrictMode.setThreadPolicy(tmpPolicy);
+ mWebServer.shutdown();
+ mWebServer = null;
+ StrictMode.setThreadPolicy(oldPolicy);
+ });
}
public void resetRequestState() {
- assertNotNull("The WebServer needs to be started", mWebServer);
- mWebServer.resetRequestState();
+ ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ mWebServer.resetRequestState();
+ });
}
public String setResponse(
String path, String responseString, List<HttpHeader> responseHeaders) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.setResponse(
- path, responseString, HttpHeader.asPairList(responseHeaders));
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.setResponse(
+ path, responseString, HttpHeader.asPairList(responseHeaders));
+ });
}
public String getAbsoluteUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getAbsoluteUrl(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getAbsoluteUrl(path);
+ });
}
public String getUserAgentUrl() {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getUserAgentUrl();
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getUserAgentUrl();
+ });
}
public String getDelayedAssetUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getDelayedAssetUrl(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getDelayedAssetUrl(path);
+ });
}
public String getRedirectingAssetUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getRedirectingAssetUrl(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getRedirectingAssetUrl(path);
+ });
}
public String getAssetUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getAssetUrl(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getAssetUrl(path);
+ });
}
public String getAuthAssetUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getAuthAssetUrl(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getAuthAssetUrl(path);
+ });
}
public String getBinaryUrl(String mimeType, int contentLength) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getBinaryUrl(mimeType, contentLength);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getBinaryUrl(mimeType, contentLength);
+ });
}
public String getAppCacheUrl() {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getAppCacheUrl();
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getAppCacheUrl();
+ });
}
public int getRequestCount() {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getRequestCount();
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getRequestCount();
+ });
}
public int getRequestCountWithPath(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getRequestCount(path);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getRequestCount(path);
+ });
}
public boolean wasResourceRequested(String url) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.wasResourceRequested(url);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.wasResourceRequested(url);
+ });
}
public HttpRequest getLastRequest(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return toHttpRequest(path, mWebServer.getLastRequest(path));
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return toHttpRequest(path, mWebServer.getLastRequest(path));
+ });
}
public HttpRequest getLastAssetRequest(String url) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return toHttpRequest(url, mWebServer.getLastAssetRequest(url));
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return toHttpRequest(url, mWebServer.getLastAssetRequest(url));
+ });
}
- public String getCookieUrl(String path) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getCookieUrl(path);
+ public String getCookieUrl(String path) {
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getCookieUrl(path);
+ });
}
- public String getSetCookieUrl(String path, String key, String value,
- String attributes) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getSetCookieUrl(path, key, value, attributes);
+ public String getSetCookieUrl(
+ String path, String key, String value, String attributes) {
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getSetCookieUrl(path, key, value, attributes);
+ });
}
public String getLinkedScriptUrl(String path, String url) {
- assertNotNull("The WebServer needs to be started", mWebServer);
- return mWebServer.getLinkedScriptUrl(path, url);
+ return ExceptionWrapper.wrap(() -> {
+ assertNotNull("The WebServer needs to be started", mWebServer);
+ return mWebServer.getLinkedScriptUrl(path, url);
+ });
}
private HttpRequest toHttpRequest(
diff --git a/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTestUtils.java b/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTestUtils.java
index cf105c2bf13..447c1a5bec1 100644
--- a/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTestUtils.java
+++ b/tests/MediaProviderTranscode/src/android/mediaprovidertranscode/cts/TranscodeTestUtils.java
@@ -16,17 +16,18 @@
package android.mediaprovidertranscode.cts;
-import static androidx.test.InstrumentationRegistry.getContext;
-
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
import static android.mediaprovidertranscode.cts.TranscodeTestConstants.INTENT_EXTRA_CALLING_PKG;
import static android.mediaprovidertranscode.cts.TranscodeTestConstants.INTENT_EXTRA_PATH;
-import static android.mediaprovidertranscode.cts.TranscodeTestConstants.OPEN_FILE_QUERY;
import static android.mediaprovidertranscode.cts.TranscodeTestConstants.INTENT_QUERY_TYPE;
+import static android.provider.DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT;
+
+import static androidx.test.InstrumentationRegistry.getContext;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.Manifest;
import android.app.ActivityManager;
@@ -38,6 +39,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
@@ -46,18 +51,13 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecInfo.VideoCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
@@ -85,6 +85,8 @@ public class TranscodeTestUtils {
private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(20);
private static final long POLLING_SLEEP_MILLIS = 100;
+ private static final String TRANSCODE_COMPAT_MANIFEST_DEVICE_CONFIG_PROPERTY_NAME =
+ "transcode_compat_manifest";
public static Uri stageHEVCVideoFile(File videoFile) throws IOException {
return stageVideoFile(videoFile, R.raw.testvideo_HEVC);
@@ -165,9 +167,16 @@ public class TranscodeTestUtils {
assertThat(numBytesWritten).isEqualTo(byteCount);
}
- public static void enableTranscodingForPackage(String packageName) throws Exception {
- executeShellCommand("device_config put storage_native_boot transcode_compat_manifest "
- + packageName + ",0");
+ public static void enableTranscodingForPackage(String packageName) {
+ getUiAutomation().adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG);
+ try {
+ final String newPropertyValue = packageName + ",0";
+ DeviceConfig.setProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ TRANSCODE_COMPAT_MANIFEST_DEVICE_CONFIG_PROPERTY_NAME, newPropertyValue,
+ /* makeDefault */ false);
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
SystemClock.sleep(1000);
}
@@ -186,8 +195,14 @@ public class TranscodeTestUtils {
executeShellCommand(command);
}
- public static void disableTranscodingForAllPackages() throws IOException {
- executeShellCommand("device_config delete storage_native_boot transcode_compat_manifest");
+ public static void disableTranscodingForAllPackages() {
+ getUiAutomation().adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG);
+ try {
+ DeviceConfig.deleteProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ TRANSCODE_COMPAT_MANIFEST_DEVICE_CONFIG_PROPERTY_NAME);
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
SystemClock.sleep(1000);
}
@@ -486,4 +501,9 @@ public class TranscodeTestUtils {
}
return false;
}
+
+ @NonNull
+ private static UiAutomation getUiAutomation() {
+ return InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java
new file mode 100644
index 00000000000..da295d0074e
--- /dev/null
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.photopicker.cts;
+
+import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvider;
+import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImage;
+import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.TIMEOUT;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.findBannerActionButton;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.findBannerDismissButton;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.getBannerPrimaryText;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.isPhotoPickerVisible;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActivityIsVisible;
+import static android.provider.MediaStore.ACTION_PICK_IMAGES;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.photopicker.cts.cloudproviders.CloudProviderPrimary;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.uiautomator.UiObject;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Photo Picker Banner Tests for common flows.
+ */
+// TODO(b/195009187): Enabling the banners requires setting allowed_cloud_providers device config.
+// We currently can't do this in R.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class PhotoPickerBannersTest extends PhotoPickerBaseTest {
+
+ private static String sPreviouslyAllowedCloudProviders;
+ private Uri mLocalMediaFileUri;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ // Store the current allowed cloud providers for reset at the end of tests.
+ sPreviouslyAllowedCloudProviders = PhotoPickerCloudUtils.getAllowedProvidersDeviceConfig();
+
+ // Override the allowed cloud providers config to enable the banners.
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(sTargetPackageName);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ // Reset the allowed cloud providers device config.
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(sPreviouslyAllowedCloudProviders);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ setCloudProvider(mContext, /* authority */ null);
+
+ // Create a local media file because if there's no media items for the picker grids,
+ // the recycler view gets hidden along with the banners.
+ mLocalMediaFileUri = createImage(mContext.getUserId(), /* isFavorite */ false).first;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (!isHardwareSupported()) {
+ // No-op, skip tear down if hardware is not supported.
+ return;
+ }
+
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+
+ deleteMedia(mLocalMediaFileUri, mContext);
+
+ setCloudProvider(mContext, /* authority */ null);
+ }
+
+ @Test
+ public void testChooseAppBannerOnDismiss() throws Exception {
+ // 1. Setting up the 'Choose App' banner.
+ setCloudMediaInfoForChooseAppBanner();
+
+ // 2. Assert that the 'Choose App' banner is visible.
+ assertThat(getBannerPrimaryText()).isEqualTo("Choose cloud media app");
+
+ // 3. Click the banner 'Dismiss' button.
+ final UiObject dismissButton = findBannerDismissButton();
+ dismissButton.click();
+
+ // 4. Assert that the Banner disappeared while the Picker is still visible.
+ assertWithMessage("Timed out waiting for the banner to disappear")
+ .that(dismissButton.waitUntilGone(TIMEOUT))
+ .isTrue();
+ assertThatPhotoPickerActivityIsVisible();
+ }
+
+ @Test
+ public void testChooseAppBannerOnActionButtonClick() throws Exception {
+ // 1. Setting up the 'Choose App' banner.
+ setCloudMediaInfoForChooseAppBanner();
+
+ // 2. Assert that the 'Choose App' banner is visible.
+ assertThat(getBannerPrimaryText()).isEqualTo("Choose cloud media app");
+
+ // 3. Click the banner 'Action' button.
+ findBannerActionButton().click();
+
+ // 4. Assert that Settings page is visible.
+ verifySettingsActivityIsVisible();
+ sDevice.pressBack();
+ }
+
+ private void setCloudMediaInfoForChooseAppBanner() {
+ // 1. Set a non-null cloud provider and launch the photo picker.
+ setCloudProvider(mContext, CloudProviderPrimary.AUTHORITY);
+ launchPickerActivity();
+ // 2. Close the photo picker.
+ mActivity.finish();
+ // 3. Set the cloud provider as None and launch the photo picker.
+ setCloudProvider(mContext, /* authority */ null);
+ launchPickerActivity();
+ }
+
+ private void launchPickerActivity() {
+ final Intent intent = new Intent(ACTION_PICK_IMAGES);
+ mActivity.startActivity(intent);
+ assertThatPhotoPickerActivityIsVisible();
+ }
+
+ private void assertThatPhotoPickerActivityIsVisible() {
+ assertWithMessage("Timed out waiting for the photo picker activity to appear")
+ .that(isPhotoPickerVisible())
+ .isTrue();
+ }
+}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
index 12a10bb6f48..067cd7821d4 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
@@ -36,6 +36,8 @@ public class PhotoPickerBaseTest {
public static int REQUEST_CODE = 42;
private static final Instrumentation sInstrumentation =
InstrumentationRegistry.getInstrumentation();
+ protected static final String sTargetPackageName =
+ sInstrumentation.getTargetContext().getPackageName();
protected static final UiDevice sDevice = UiDevice.getInstance(sInstrumentation);
protected GetResultActivity mActivity;
@@ -64,7 +66,7 @@ public class PhotoPickerBaseTest {
sDevice.waitForIdle();
}
- private static boolean isHardwareSupported() {
+ static boolean isHardwareSupported() {
// These UI tests are not optimised for Watches, TVs, Auto;
// IoT devices do not have a UI to run these UI tests
PackageManager pm = sInstrumentation.getContext().getPackageManager();
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
index 96d3f933f03..59b552cdddf 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
@@ -16,18 +16,26 @@
package android.photopicker.cts;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvider;
import static android.photopicker.cts.PickerProviderMediaGenerator.syncCloudProvider;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
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 android.app.UiAutomation;
import android.content.ClipData;
import android.content.Context;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
@@ -36,6 +44,9 @@ import java.util.Collections;
import java.util.List;
public class PhotoPickerCloudUtils {
+ private static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
+ private static final String ALLOWED_CLOUD_PROVIDERS_KEY = "allowed_cloud_providers";
+
public static List<String> extractMediaIds(ClipData clipData, int minCount) {
final int count = clipData.getItemCount();
assertThat(count).isAtLeast(minCount);
@@ -97,4 +108,41 @@ public class PhotoPickerCloudUtils {
assertThat(mediaIds).contains(contained);
assertThat(mediaIds).containsNoneIn(Collections.singletonList(notContained));
}
+
+ @Nullable
+ static String getAllowedProvidersDeviceConfig() {
+ getUiAutomation().adoptShellPermissionIdentity(READ_DEVICE_CONFIG);
+ try {
+ return DeviceConfig.getProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ ALLOWED_CLOUD_PROVIDERS_KEY);
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
+ }
+
+ static void setAllowedProvidersDeviceConfig(@Nullable String allowedCloudProviders) {
+ getUiAutomation().adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG);
+ try {
+ if (allowedCloudProviders == null) {
+ DeviceConfig.deleteProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ ALLOWED_CLOUD_PROVIDERS_KEY);
+ assertWithMessage("Failed to delete the allowed cloud providers device config")
+ .that(getAllowedProvidersDeviceConfig())
+ .isNull();
+ } else {
+ DeviceConfig.setProperty(NAMESPACE_STORAGE_NATIVE_BOOT, ALLOWED_CLOUD_PROVIDERS_KEY,
+ allowedCloudProviders, /* makeDefault */ false);
+ assertWithMessage("Failed to update the allowed cloud providers device config")
+ .that(getAllowedProvidersDeviceConfig())
+ .isEqualTo(allowedCloudProviders);
+ }
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
+ }
+
+ @NonNull
+ private static UiAutomation getUiAutomation() {
+ return InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
index f818c10baaf..d8cc456fe32 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
@@ -36,8 +36,6 @@ import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
-import java.io.IOException;
-
/**
* Photo Picker tests for settings page launched from the overflow menu in PhotoPickerActivity or
* the Settings app.
@@ -47,37 +45,22 @@ import java.io.IOException;
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
public class PhotoPickerSettingsTest extends PhotoPickerBaseTest {
- private static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
- private static final String ALLOWED_CLOUD_PROVIDERS_KEY = "allowed_cloud_providers";
-
private static String sPreviouslyAllowedCloudProviders;
@BeforeClass
- public static void setUpBeforeClass() throws Exception {
+ public static void setUpBeforeClass() {
// Store current allowed cloud providers for reset at the end of tests.
- sPreviouslyAllowedCloudProviders = getAllowedProvidersDeviceConfig();
+ sPreviouslyAllowedCloudProviders = PhotoPickerCloudUtils.getAllowedProvidersDeviceConfig();
// Enable Settings menu item in PhotoPickerActivity's overflow menu.
- sDevice.executeShellCommand(
- String.format("device_config put %s %s not_empty", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- Assume.assumeTrue(!getAllowedProvidersDeviceConfig().isBlank());
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(
+ /* allowedCloudProviders */ "not_empty");
}
@AfterClass
- public static void tearDownClass() throws Exception {
+ public static void tearDownClass() {
// Reset allowed cloud providers device config.
- if (sPreviouslyAllowedCloudProviders == null
- || sPreviouslyAllowedCloudProviders.isBlank()) {
- // Delete the device config since `device_config put` does not support empty values.
- sDevice.executeShellCommand(
- String.format("device_config delete %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- } else {
- sDevice.executeShellCommand(
- String.format("device_config put %s %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY, sPreviouslyAllowedCloudProviders));
- }
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(sPreviouslyAllowedCloudProviders);
}
@Test
@@ -93,16 +76,10 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest {
PhotoPickerUiUtils.clickAndWait(sDevice, settingsMenuItem);
// Verify PhotoPickerSettingsActivity is launched and visible.
- verifySettingsActivityIsVisible(sDevice);
+ verifySettingsActivityIsVisible();
verifySettingsActionBarIsVisible();
verifySettingsTitleIsVisible();
verifySettingsDescriptionIsVisible();
verifySettingsFragmentContainerExists();
}
-
- private static String getAllowedProvidersDeviceConfig() throws IOException {
- return sDevice.executeShellCommand(
- String.format("device_config get %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PickerProviderMediaGenerator.java b/tests/PhotoPicker/src/android/photopicker/cts/PickerProviderMediaGenerator.java
index 5110781914f..216b5de1d1f 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PickerProviderMediaGenerator.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PickerProviderMediaGenerator.java
@@ -432,8 +432,7 @@ public class PickerProviderMediaGenerator {
}
albumId = bundle.getString(CloudMediaProviderContract.EXTRA_ALBUM_ID, null);
- mimeType = bundle.getString(CloudMediaProviderContract.EXTRA_MIME_TYPE,
- null);
+ mimeType = bundle.getString(Intent.EXTRA_MIME_TYPES, null);
sizeBytes = bundle.getLong(CloudMediaProviderContract.EXTRA_SIZE_LIMIT_BYTES, 0);
generation = bundle.getLong(CloudMediaProviderContract.EXTRA_SYNC_GENERATION, 0);
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
index 85b0e89fefd..855a0b93982 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
@@ -34,7 +34,7 @@ import java.util.List;
public class PhotoPickerUiUtils {
public static final long SHORT_TIMEOUT = 5 * DateUtils.SECOND_IN_MILLIS;
- private static final long TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS;
+ public static final long TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS;
public static final String REGEX_PACKAGE_NAME =
"com(.google)?.android.providers.media(.module)?";
@@ -158,7 +158,7 @@ public class PhotoPickerUiUtils {
.isTrue();
}
- public static void verifySettingsActivityIsVisible(UiDevice uiDevice) {
+ public static void verifySettingsActivityIsVisible() {
// id/settings_activity_root is the root layout in activity_photo_picker_settings.xml
assertWithMessage("Timed out waiting for settings activity to appear")
.that(new UiObject(new UiSelector()
@@ -171,4 +171,23 @@ public class PhotoPickerUiUtils {
uiObject.click();
uiDevice.waitForIdle();
}
+
+ public static String getBannerPrimaryText() throws Exception {
+ final UiObject bannerPrimaryText = new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/banner_primary_text"));
+ assertWithMessage("Timed out waiting for the banner to appear")
+ .that(bannerPrimaryText.waitForExists(TIMEOUT))
+ .isTrue();
+ return bannerPrimaryText.getText();
+ }
+
+ public static UiObject findBannerDismissButton() {
+ return new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/dismiss_button"));
+ }
+
+ public static UiObject findBannerActionButton() {
+ return new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/action_button"));
+ }
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
index e36d1ee0c20..64cc0f126bc 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFingerprintGestureTest.java
@@ -18,6 +18,7 @@ import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -90,9 +91,10 @@ public class AccessibilityFingerprintGestureTest {
@Test
public void testGestureDetectionListener_whenAuthenticationStartsAndStops_calledBack() {
- if (!mFingerprintGestureController.isGestureDetectionAvailable()) {
- return;
- }
+ assumeTrue("Fingerprint gesture detection is not available",
+ mFingerprintGestureController.isGestureDetectionAvailable());
+ assumeTrue("No enrolled fingerprints; cannot open fingerprint prompt",
+ mFingerprintManager.hasEnrolledFingerprints());
// Launch an activity to make sure we're in the foreground
mActivityRule.launchActivity(null);
mFingerprintGestureController.registerFingerprintGestureCallback(
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index 11bc2047c3f..a17e5104ff0 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -41,6 +41,7 @@ android_test {
srcs: [
"src/**/*.java",
"src/**/*.kt",
+ "app/src/android/app/stubs/RemoteActivity.java",
"NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl",
],
// Tag this module as a cts test artifact
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index b78bb087c3f..7367ba98a2d 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -66,6 +66,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<application android:label="Android TestCase"
android:icon="@drawable/size_48x48"
@@ -591,6 +592,10 @@
</intent-filter>
</receiver>
+ <activity android:name="android.app.stubs.RemoteActivity"
+ android:process=":remote"
+ android:excludeFromRecents="true"
+ android:exported="true" />
</application>
</manifest>
diff --git a/tests/app/app/src/android/app/stubs/RemoteActivity.java b/tests/app/app/src/android/app/stubs/RemoteActivity.java
new file mode 100644
index 00000000000..0af1cbaf7cf
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/RemoteActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * An empty helper activity.
+ */
+public final class RemoteActivity extends Activity {
+
+ /** Extras to the launching intent */
+ public static final String EXTRA_CALLBACK = "callback";
+
+ private final IBinder mStub = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case IBinder.FIRST_CALL_TRANSACTION:
+ finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Intent intent = getIntent();
+ final IBinder callback = intent.getExtras().getBinder(EXTRA_CALLBACK);
+ final Parcel data = Parcel.obtain();
+ try {
+ data.writeStrongBinder(mStub);
+ callback.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
+ } catch (RemoteException e) {
+ } finally {
+ data.recycle();
+ }
+ }
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index e837f9a5f6f..3c69b092340 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -61,6 +61,7 @@ import android.app.stubs.CommandReceiver;
import android.app.stubs.LocalForegroundService;
import android.app.stubs.MockApplicationActivity;
import android.app.stubs.MockService;
+import android.app.stubs.RemoteActivity;
import android.app.stubs.ScreenOnActivity;
import android.app.stubs.TestHomeActivity;
import android.app.stubs.TrimMemService;
@@ -184,7 +185,7 @@ public class ActivityManagerTest {
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTargetContext = mInstrumentation.getTargetContext();
- mActivityManager = (ActivityManager) mInstrumentation.getContext()
+ mActivityManager = (ActivityManager) mTargetContext
.getSystemService(Context.ACTIVITY_SERVICE);
mPackageManager = mInstrumentation.getContext().getPackageManager();
mStartedActivityList = new ArrayList<Activity>();
@@ -192,6 +193,7 @@ public class ActivityManagerTest {
mAppStandbyEnabled = AppStandbyUtils.isAppStandbyEnabled();
mAutomotiveDevice = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
mLeanbackOnly = mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
+ toggleScreenOn(true);
startSubActivity(ScreenOnActivity.class);
drainOrderedBroadcastQueue(2);
}
@@ -2310,4 +2312,123 @@ public class ActivityManagerTest {
return context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TELEVISION);
}
+
+ @Test
+ public void testKillBackgroundProcess() throws Exception {
+ final String otherPackage = "com.android.app1";
+ final ApplicationInfo ai1 = mTargetContext.getPackageManager()
+ .getApplicationInfo(otherPackage, 0);
+ final WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, Process.myUid(),
+ WAITFOR_MSEC);
+ final WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, ai1.uid,
+ WAITFOR_MSEC);
+ try {
+ launchHome();
+
+ // Since we're running instrumentation, our proc state will stay above FGS.
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_FG_SERVICE);
+
+ // Start an activity in another process in our package, our proc state will goto TOP.
+ final CountDownLatch remoteBinderDeathLatch1 = startRemoteActivityAndLinkToDeath(
+ new ComponentName(mTargetContext, RemoteActivity.class),
+ uid1Watcher);
+
+ final CountDownLatch remoteBinderDeathLatch2 = startRemoteActivityAndLinkToDeath(
+ new ComponentName(otherPackage, STUB_PACKAGE_NAME + ".RemoteActivity"),
+ uid2Watcher);
+
+ // Launch home again so our activity will be backgrounded.
+ launchHome();
+
+ // The uid goes back to FGS state,
+ // but the process with the remote activity should have been in the background.
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_FG_SERVICE);
+
+ // And the test package should be in background too.
+ uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_LAST);
+
+ // Now, try to kill the background process of our own, it should succeed.
+ mActivityManager.killBackgroundProcesses(mTargetContext.getPackageName());
+
+ assertTrue("We should be able to kill our own process",
+ remoteBinderDeathLatch1.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+
+ // Try to kill the background process of other app, it should fail.
+ mActivityManager.killBackgroundProcesses(otherPackage);
+
+ assertFalse("We should be able to kill the processes of other package",
+ remoteBinderDeathLatch2.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+
+ // Adopt the permission, we should be able to kill it now.
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ android.Manifest.permission.FORCE_STOP_PACKAGES);
+
+ mActivityManager.killBackgroundProcesses(otherPackage);
+
+ assertTrue("We should be able to kill the processes of other package",
+ remoteBinderDeathLatch2.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+ } finally {
+ uid1Watcher.finish();
+ uid2Watcher.finish();
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ finishAndRemoveTask(new ComponentName(mTargetContext, RemoteActivity.class));
+ }
+ }
+
+ private void finishAndRemoveTask(ComponentName activity) {
+ for (ActivityManager.AppTask task : mActivityManager.getAppTasks()) {
+ final ActivityManager.RecentTaskInfo info = task.getTaskInfo();
+ if (info != null && activity.equals(info.topActivity)) {
+ task.finishAndRemoveTask();
+ break;
+ }
+ }
+ }
+
+ private CountDownLatch startRemoteActivityAndLinkToDeath(ComponentName activity,
+ WatchUidRunner uidWatcher) throws Exception {
+ final IBinder[] remoteBinderHolder = new IBinder[1];
+ final CountDownLatch remoteBinderLatch = new CountDownLatch(1);
+ final IBinder binder = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case IBinder.FIRST_CALL_TRANSACTION:
+ remoteBinderHolder[0] = data.readStrongBinder();
+ remoteBinderLatch.countDown();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+ final CountDownLatch remoteBinderDeathLatch = new CountDownLatch(1);
+ final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ remoteBinderDeathLatch.countDown();
+ }
+ };
+ final Intent intent = new Intent();
+ intent.setComponent(activity);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Bundle extras = new Bundle();
+ extras.putBinder(RemoteActivity.EXTRA_CALLBACK, binder);
+ intent.putExtras(extras);
+ mTargetContext.startActivity(intent);
+
+ uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
+ assertTrue("Failed to receive the callback from remote activity",
+ remoteBinderLatch.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+ assertNotNull(remoteBinderHolder[0]);
+ remoteBinderHolder[0].linkToDeath(recipient, 0);
+
+ // Sleep a while to let things go through.
+ Thread.sleep(WAIT_TIME);
+ return remoteBinderDeathLatch;
+ }
}
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index cd1de26dd66..f654724b78f 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -300,9 +300,6 @@ class NotificationTemplateTest : NotificationTemplateTestBase() {
checkViews(builder.createBigContentView()) {
val pictureView = requireViewByIdName<ImageView>("big_picture")
assertThat(pictureView.visibility).isEqualTo(View.VISIBLE)
- assertThat(pictureView.width.toFloat())
- .isWithin(1f)
- .of((pictureView.height * 4 / 3).toFloat())
assertThat(pictureView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
}
}
diff --git a/tests/autofillservice/res/layout/scrollable_login_activity.xml b/tests/autofillservice/res/layout/scrollable_login_activity.xml
new file mode 100644
index 00000000000..dfa5227a458
--- /dev/null
+++ b/tests/autofillservice/res/layout/scrollable_login_activity.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="vertical" >
+
+ <ScrollView android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <include layout="@layout/login_activity" />
+
+ </LinearLayout>
+
+ </ScrollView>
+
+</LinearLayout>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index 6dd4d1ae033..381eefb0a6c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -543,10 +543,9 @@ public class SessionLifecycleTest extends AutoFillServiceTestCase.ManualActivity
// It works fine for portrait but for the platforms that the default orientation
// is landscape, e.g. automotive. Depending on the height of the IME, the ID_LOGIN
// button may not be visible.
- // In order to avoid that,
- // generate back key event to hide IME before pressing ID_LOGIN button.
- mUiBot.pressBack();
+ // In order to avoid that, scroll until the ID_LOGIN button appears.
+ mUiBot.scrollToTextObject(ID_LOGIN);
mUiBot.selectByRelativeId(ID_LOGIN);
mUiBot.assertSaveShowing(SAVE_DATA_TYPE_USERNAME);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/OutOfProcessLoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/OutOfProcessLoginActivity.java
index 4cab12cf18e..ca910901bee 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/activities/OutOfProcessLoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/OutOfProcessLoginActivity.java
@@ -41,7 +41,7 @@ public class OutOfProcessLoginActivity extends Activity {
Log.i(TAG, "onCreate(" + savedInstanceState + ")");
super.onCreate(savedInstanceState);
- setContentView(R.layout.login_activity);
+ setContentView(R.layout.scrollable_login_activity);
findViewById(R.id.login).setOnClickListener((v) -> finish());
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index 4ee066f268f..70f0c062e51 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -40,8 +40,8 @@ import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.RECORD;
import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.VGA;
import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.YUV;
-import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
@@ -78,7 +78,6 @@ import android.media.CamcorderProfile;
import android.media.Image;
import android.media.ImageReader;
import android.media.ImageWriter;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
@@ -95,12 +94,11 @@ import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
-import java.util.Iterator;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.LinkedBlockingQueue;
/**
* Tests exercising edge cases in camera setup, configuration, and usage.
@@ -217,28 +215,6 @@ public class RobustnessTest extends Camera2AndroidTestCase {
* Test for making sure the mandatory stream combinations work as expected.
*/
private void testMandatoryOutputCombinations(boolean maxResolution) throws Exception {
- final int AVAILABILITY_TIMEOUT_MS = 10;
- final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
- new LinkedBlockingQueue<>();
- CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
- @Override
- public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
- unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
- }
- };
-
- mCameraManager.registerAvailabilityCallback(ac, mHandler);
- Set<Pair<String, String>> unavailablePhysicalCameras = new HashSet<Pair<String, String>>();
- Pair<String, String> candidatePhysicalIds =
- unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
- java.util.concurrent.TimeUnit.MILLISECONDS);
- while (candidatePhysicalIds != null) {
- unavailablePhysicalCameras.add(candidatePhysicalIds);
- candidatePhysicalIds =
- unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
- java.util.concurrent.TimeUnit.MILLISECONDS);
- }
- mCameraManager.unregisterAvailabilityCallback(ac);
CameraCharacteristics.Key<MandatoryStreamCombination []> ck =
CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS;
@@ -276,22 +252,10 @@ public class RobustnessTest extends Camera2AndroidTestCase {
if (mStaticInfo.isLogicalMultiCamera()) {
Set<String> physicalCameraIds =
mStaticInfo.getCharacteristics().getPhysicalCameraIds();
- boolean skipTest = false;
for (String physicalId : physicalCameraIds) {
if (Arrays.asList(mCameraIdsUnderTest).contains(physicalId)) {
// If physicalId is advertised in camera ID list, do not need to test
// its stream combination through logical camera.
- skipTest = true;
- }
- for (Pair<String, String> unavailPhysicalCam : unavailablePhysicalCameras) {
- if (unavailPhysicalCam.first.equals(id) ||
- unavailPhysicalCam.second.equals(physicalId)) {
- // This particular physical camera isn't available. Skip.
- skipTest = true;
- break;
- }
- }
- if (skipTest) {
continue;
}
StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId);
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 2e0a212502e..de97acc76b7 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -301,7 +301,7 @@
android:exported="true"/>
<activity android:name=".ShowWhenLockedDialogActivity"
android:exported="true"
- android:theme="@android:style/Theme.Material.Dialog"/>
+ android:theme="@style/ShowWhenLockedDialogTheme"/>
<activity android:name=".ShowWhenLockedTranslucentActivity"
android:exported="true"
android:theme="@android:style/Theme.Translucent"/>
@@ -332,10 +332,11 @@
android:exported="true"
android:configChanges="uiMode"/>
<activity android:name=".FontScaleActivity"
+ android:configChanges="screenSize|screenLayout"
android:exported="true"/>
<activity android:name=".FontScaleNoRelaunchActivity"
android:exported="true"
- android:configChanges="fontScale"/>
+ android:configChanges="fontScale|screenSize|screenLayout"/>
<activity android:name=".DisplayAccessCheckEmbeddingActivity"
android:allowEmbedded="true"
android:exported="true"/>
diff --git a/tests/framework/base/windowmanager/app/res/values-watch/styles.xml b/tests/framework/base/windowmanager/app/res/values-watch/styles.xml
new file mode 100644
index 00000000000..14da3216ffc
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/res/values-watch/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="ShowWhenLockedDialogTheme" parent="@android:style/Theme.Material.Dialog">
+ <!-- Wear dialog theme has been converted to non-floating, but this breaks occluding -->
+ <item name="@android:windowIsFloating">true</item>
+ <!-- Likewise, for the purpose of CTS, make this non-swipeable, as there are visibility
+ implications there as well -->
+ <item name="@android:windowSwipeToDismiss">false</item>
+ </style>
+</resources>
diff --git a/tests/framework/base/windowmanager/app/res/values/styles.xml b/tests/framework/base/windowmanager/app/res/values/styles.xml
index 43f60ebe9a7..d0e35c0c053 100644
--- a/tests/framework/base/windowmanager/app/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/app/res/values/styles.xml
@@ -101,4 +101,7 @@
<item name="android:windowLayoutInDisplayCutoutMode">always</item>
<item name="android:windowSoftInputMode">stateHidden</item>
</style>
+ <style name="ShowWhenLockedDialogTheme" parent="@android:style/Theme.Material.Dialog">
+ <!-- no-op except on Wear, where dialog theme has been converted to non-floating -->
+ </style>
</resources>
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index c2752e6241e..4326f7d7ccc 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -39,6 +39,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNotNull;
import android.graphics.Rect;
+import android.server.wm.IgnoreOrientationRequestSession;
import android.server.wm.jetpack.utils.TestActivity;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestValueCountJavaConsumer;
@@ -167,56 +168,66 @@ public class ExtensionWindowLayoutComponentTest extends WindowManagerJetpackTest
@Test
public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates()
- throws ExecutionException, InterruptedException, TimeoutException {
+ throws InterruptedException {
mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
assumeHasDisplayFeatures(mWindowLayoutInfo);
- TestConfigChangeHandlingActivity configHandlingActivity
+ final TestConfigChangeHandlingActivity configHandlingActivity
= (TestConfigChangeHandlingActivity) startActivityNewTask(
TestConfigChangeHandlingActivity.class);
- setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
- ORIENTATION_PORTRAIT);
- final WindowLayoutInfo portraitWindowLayoutInfo = getExtensionWindowLayoutInfo(
- configHandlingActivity);
- final Rect portraitBounds = getActivityBounds(configHandlingActivity);
- final Rect portraitMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
-
- setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
- ORIENTATION_LANDSCAPE);
- final WindowLayoutInfo landscapeWindowLayoutInfo = getExtensionWindowLayoutInfo(
- configHandlingActivity);
- final Rect landscapeBounds = getActivityBounds(configHandlingActivity);
- final Rect landscapeMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
-
- final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
- portraitMaximumBounds, landscapeMaximumBounds);
- assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
- portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
+ try (IgnoreOrientationRequestSession session =
+ new IgnoreOrientationRequestSession(false /* enable */)) {
+ setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
+ ORIENTATION_PORTRAIT);
+ final WindowLayoutInfo portraitWindowLayoutInfo = getExtensionWindowLayoutInfo(
+ configHandlingActivity);
+ final Rect portraitBounds = getActivityBounds(configHandlingActivity);
+ final Rect portraitMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
+
+ setActivityOrientationActivityHandlesOrientationChanges(configHandlingActivity,
+ ORIENTATION_LANDSCAPE);
+ final WindowLayoutInfo landscapeWindowLayoutInfo = getExtensionWindowLayoutInfo(
+ configHandlingActivity);
+ final Rect landscapeBounds = getActivityBounds(configHandlingActivity);
+ final Rect landscapeMaximumBounds = getMaximumActivityBounds(configHandlingActivity);
+
+ final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
+ portraitMaximumBounds, landscapeMaximumBounds);
+ assertTrue(doesDisplayRotateForOrientation);
+ assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
+ portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
+ }
}
@Test
public void testGetWindowLayoutInfo_windowRecreated_windowLayoutUpdates()
- throws ExecutionException, InterruptedException, TimeoutException {
- mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
- assumeHasDisplayFeatures(mWindowLayoutInfo);
-
- setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
- ORIENTATION_PORTRAIT);
- final WindowLayoutInfo portraitWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
- final Rect portraitBounds = getActivityBounds(mActivity);
- final Rect portraitMaximumBounds = getMaximumActivityBounds(mActivity);
-
- setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
- ORIENTATION_LANDSCAPE);
- final WindowLayoutInfo landscapeWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
- final Rect landscapeBounds = getActivityBounds(mActivity);
- final Rect landscapeMaximumBounds = getMaximumActivityBounds(mActivity);
-
- final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
- portraitMaximumBounds, landscapeMaximumBounds);
- assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
- portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
+ throws InterruptedException {
+ try (IgnoreOrientationRequestSession session =
+ new IgnoreOrientationRequestSession(false /* enable */)) {
+ mWindowLayoutInfo = getExtensionWindowLayoutInfo(mActivity);
+ assumeHasDisplayFeatures(mWindowLayoutInfo);
+
+ setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
+ ORIENTATION_PORTRAIT);
+ final WindowLayoutInfo portraitWindowLayoutInfo =
+ getExtensionWindowLayoutInfo(mActivity);
+ final Rect portraitBounds = getActivityBounds(mActivity);
+ final Rect portraitMaximumBounds = getMaximumActivityBounds(mActivity);
+
+ setActivityOrientationActivityDoesNotHandleOrientationChanges(mActivity,
+ ORIENTATION_LANDSCAPE);
+ final WindowLayoutInfo landscapeWindowLayoutInfo =
+ getExtensionWindowLayoutInfo(mActivity);
+ final Rect landscapeBounds = getActivityBounds(mActivity);
+ final Rect landscapeMaximumBounds = getMaximumActivityBounds(mActivity);
+
+ final boolean doesDisplayRotateForOrientation = doesDisplayRotateForOrientation(
+ portraitMaximumBounds, landscapeMaximumBounds);
+ assertTrue(doesDisplayRotateForOrientation);
+ assertEqualWindowLayoutInfo(portraitWindowLayoutInfo, landscapeWindowLayoutInfo,
+ portraitBounds, landscapeBounds, doesDisplayRotateForOrientation);
+ }
}
/**
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
index f7b352f8e99..143f7c00e36 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
@@ -16,9 +16,6 @@
package android.server.wm.jetpack.utils;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getActivityBounds;
-import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.getMaximumActivityBounds;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -38,8 +35,6 @@ import androidx.window.extensions.layout.FoldingFeature;
import androidx.window.extensions.layout.WindowLayoutComponent;
import androidx.window.extensions.layout.WindowLayoutInfo;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -109,7 +104,7 @@ public class ExtensionUtil {
@Nullable
public static WindowLayoutInfo getExtensionWindowLayoutInfo(Activity activity)
- throws ExecutionException, InterruptedException, TimeoutException {
+ throws InterruptedException {
WindowLayoutComponent windowLayoutComponent = getExtensionWindowLayoutComponent();
if (windowLayoutComponent == null) {
return null;
@@ -117,7 +112,14 @@ public class ExtensionUtil {
TestValueCountJavaConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
new TestValueCountJavaConsumer<>();
windowLayoutComponent.addWindowLayoutInfoListener(activity, windowLayoutInfoConsumer);
- return windowLayoutInfoConsumer.waitAndGet();
+ WindowLayoutInfo info = windowLayoutInfoConsumer.waitAndGet();
+
+ // The default implementation only allows a single listener per activity. Since we are using
+ // a local windowLayoutInfoConsumer within this function, we must remember to clean up.
+ // Otherwise, subsequent calls to addWindowLayoutInfoListener with the same activity will
+ // fail to have its callback registered.
+ windowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
+ return info;
}
@NonNull
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
index 2d4260ccdd5..d47cc6d76db 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityTransitionTests.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.server.wm.ActivityTransitionTests.EdgeExtensionActivity.BOTTOM;
import static android.server.wm.ActivityTransitionTests.EdgeExtensionActivity.DIRECTION_KEY;
@@ -114,7 +115,9 @@ public class ActivityTransitionTests extends ActivityManagerTestBase {
final Intent intent = new Intent(mContext, LauncherActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- return (LauncherActivity) instrumentation.startActivitySync(intent);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ return (LauncherActivity) instrumentation.startActivitySync(intent, options.toBundle());
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
index 79bbe9c5ffa..a975e5a8680 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
@@ -65,7 +65,6 @@ import org.junit.Test;
public class AssistantStackTests extends ActivityManagerTestBase {
private int mAssistantDisplayId = DEFAULT_DISPLAY;
- private int mDefaultWindowingMode;
public void setUp() throws Exception {
super.setUp();
@@ -76,7 +75,6 @@ public class AssistantStackTests extends ActivityManagerTestBase {
WindowManagerState.Task assistantStack =
mWmState.getRootTaskByActivityType(ACTIVITY_TYPE_ASSISTANT);
mAssistantDisplayId = assistantStack.mDisplayId;
- mDefaultWindowingMode = getDefaultDisplayWindowingMode();
}
}
@@ -92,7 +90,7 @@ public class AssistantStackTests extends ActivityManagerTestBase {
// Ensure that the activity launched in the fullscreen assistant stack
assertAssistantStackExists();
// In a multi-window environment the assistant might not be fullscreen
- assumeTrue(mDefaultWindowingMode == WINDOWING_MODE_FULLSCREEN);
+ assumeTrue(getDefaultDisplayWindowingMode() == WINDOWING_MODE_FULLSCREEN);
assertTrue("Expected assistant stack to be fullscreen",
mWmState.getRootTaskByActivityType(
ACTIVITY_TYPE_ASSISTANT).isFullscreen());
@@ -134,7 +132,7 @@ public class AssistantStackTests extends ActivityManagerTestBase {
@Test
public void testAssistantStackLaunchNewTask() throws Exception {
- assertAssistantStackCanLaunchAndReturnFromNewTask(mDefaultWindowingMode);
+ assertAssistantStackCanLaunchAndReturnFromNewTask();
}
@Test
@@ -151,7 +149,7 @@ public class AssistantStackTests extends ActivityManagerTestBase {
//assertAssistantStackCanLaunchAndReturnFromNewTask(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
}
- private void assertAssistantStackCanLaunchAndReturnFromNewTask(int expectedWindowingMode)
+ private void assertAssistantStackCanLaunchAndReturnFromNewTask()
throws Exception {
// Enable the assistant and launch an assistant activity which will launch a new task
try (final AssistantSession assistantSession = new AssistantSession()) {
@@ -161,8 +159,7 @@ public class AssistantStackTests extends ActivityManagerTestBase {
extraString(EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY)),
extraString(EXTRA_ASSISTANT_DISPLAY_ID, Integer.toString(mAssistantDisplayId)));
// Ensure that the fullscreen stack is on top and the test activity is now visible
- waitForValidStateWithActivityTypeAndWindowingMode(
- TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, expectedWindowingMode);
+ waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD);
}
if (isAssistantOnTopOfDream()) {
@@ -175,11 +172,13 @@ public class AssistantStackTests extends ActivityManagerTestBase {
mWmState.assertFocusedRootTask("Assistant stack should be focused.",
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
} else {
+ final int testActivityWindowingMode =
+ mWmState.getTaskDisplayArea(TEST_ACTIVITY).getWindowingMode();
mWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY);
mWmState.assertFrontStack("TestActivity stack should be on top.",
- expectedWindowingMode, ACTIVITY_TYPE_STANDARD);
+ testActivityWindowingMode, ACTIVITY_TYPE_STANDARD);
mWmState.assertFocusedRootTask("TestActivity stack should be focused.",
- expectedWindowingMode, ACTIVITY_TYPE_STANDARD);
+ testActivityWindowingMode, ACTIVITY_TYPE_STANDARD);
}
// Now, tell it to finish itself and ensure that the assistant stack is brought back forward
@@ -211,15 +210,17 @@ public class AssistantStackTests extends ActivityManagerTestBase {
mWmState.waitFor((amState) -> !amState.containsActivity(ASSISTANT_ACTIVITY),
getActivityName(ASSISTANT_ACTIVITY) + " finished");
}
- waitForValidStateWithActivityTypeAndWindowingMode(
- TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, mDefaultWindowingMode);
+ waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD);
waitAndAssertTopResumedActivity(TEST_ACTIVITY, mAssistantDisplayId,
"TestActivity should be resumed");
mWmState.assertFocusedActivity("TestActivity should be focused", TEST_ACTIVITY);
- mWmState.assertFrontStack("Fullscreen stack should be on top.",
- mDefaultWindowingMode, ACTIVITY_TYPE_STANDARD);
- mWmState.assertFocusedRootTask("Fullscreen stack should be focused.",
- mDefaultWindowingMode, ACTIVITY_TYPE_STANDARD);
+
+ final int testActivityWindowingMode =
+ mWmState.getTaskDisplayArea(TEST_ACTIVITY).getWindowingMode();
+ mWmState.assertFrontStack("TestActivity stack should be on top.",
+ testActivityWindowingMode, ACTIVITY_TYPE_STANDARD);
+ mWmState.assertFocusedRootTask("TestActivity stack should be focused.",
+ testActivityWindowingMode, ACTIVITY_TYPE_STANDARD);
}
@Test
@@ -273,8 +274,7 @@ public class AssistantStackTests extends ActivityManagerTestBase {
launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, "true"),
extraString(EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY)));
- waitForValidStateWithActivityTypeAndWindowingMode(
- TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, mDefaultWindowingMode);
+ waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD);
final ComponentName homeActivity = mWmState.getHomeActivityName();
int windowingMode = mWmState.getFocusedRootTaskWindowingMode();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ConfigChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ConfigChangeTests.java
index c1396d6e5a0..6109decbffe 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ConfigChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ConfigChangeTests.java
@@ -253,17 +253,23 @@ public class ConfigChangeTests extends ActivityManagerTestBase {
separateTestJournal();
fontScaleSession.set(fontScale);
mWmState.computeState(activityName);
- assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1);
+ // The number of config changes could be greater than expected as there may have
+ // other configuration change events triggered after font scale changed, such as
+ // NavigationBar recreated.
+ new ActivityLifecycleCounts(activityName).assertCountWithRetry(
+ "relaunch or config changed",
+ countSpec(ActivityCallback.ON_DESTROY, CountSpec.EQUALS, relaunch ? 1 : 0),
+ countSpec(ActivityCallback.ON_CREATE, CountSpec.EQUALS, relaunch ? 1 : 0),
+ countSpec(ActivityCallback.ON_CONFIGURATION_CHANGED,
+ CountSpec.GREATER_THAN_OR_EQUALS, relaunch ? 0 : 1));
// Verify that the display metrics are updated, and therefore the text size is also
// updated accordingly.
final Bundle changedExtras = TestJournalContainer.get(activityName).extras;
+ final float scale = fontScale;
waitForOrFail("reported fontPixelSize from " + activityName,
- () -> changedExtras.containsKey(EXTRA_FONT_PIXEL_SIZE));
- final int expectedFontPixelSize =
- scaledPixelsToPixels(EXPECTED_FONT_SIZE_SP, fontScale, densityDpi);
- assertEquals("Expected font pixel size should match", expectedFontPixelSize,
- changedExtras.getInt(EXTRA_FONT_PIXEL_SIZE));
+ () -> scaledPixelsToPixels(EXPECTED_FONT_SIZE_SP, scale, densityDpi)
+ == changedExtras.getInt(EXTRA_FONT_PIXEL_SIZE));
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ForceRelayoutTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/ForceRelayoutTestBase.java
index ac06678d80b..713958d94a4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ForceRelayoutTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ForceRelayoutTestBase.java
@@ -28,6 +28,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import android.app.Activity;
+import android.content.res.Resources;
+import android.content.pm.PackageManager;
import android.graphics.Insets;
import android.os.Bundle;
import android.view.View;
@@ -55,6 +57,7 @@ public class ForceRelayoutTestBase {
assertNotNull("test setup failed", activity.mLastContentInsets);
assumeFalse(Insets.NONE.equals(activity.mLastContentInsets.getInsetsIgnoringVisibility(
statusBars() | navigationBars())));
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
activity.mLayoutHappened = false;
@@ -113,4 +116,15 @@ public class ForceRelayoutTestBase {
setContentView(view);
}
}
+
+ private static boolean remoteInsetsControllerControlsSystemBars() {
+ return InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()
+ .getBoolean(android.R.bool.config_remoteInsetsControllerControlsSystemBars);
+ }
+
+ private boolean isCar() {
+ PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
+ .getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
index 55eae8c3585..81173bbe767 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
@@ -361,6 +361,7 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
final Rect keepClearRect = new Rect(0, 0, 25, 25);
final View v = createTestViewInActivity(activity, keepClearRect);
+ final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay();
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
assertSameElementsEventually(Arrays.asList(keepClearRect),
() -> getKeepClearRectsForActivity(activity));
@@ -372,15 +373,16 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
() -> getKeepClearRectsForActivity(activity));
- final List<Rect> expectedRectsInScreenSpace =
- getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, activity.getComponentName());
- assertSameElementsEventually(expectedRectsInScreenSpace,
+ final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>();
+ expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay);
+ expectedRectsOnDisplay.addAll(
+ getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, activity.getComponentName()));
+ assertSameElementsEventually(expectedRectsOnDisplay,
() -> getKeepClearRectsOnDefaultDisplay());
activity.finishAndRemoveTask();
- assertTrue(Collections.disjoint(
- expectedRectsInScreenSpace,
- getKeepClearRectsOnDefaultDisplay()));
+ assertSameElementsEventually(prevKeepClearRectsOnDisplay,
+ () -> getKeepClearRectsOnDefaultDisplay());
}
@Test
@@ -419,6 +421,7 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
final Rect viewBounds = new Rect(0, 0, 25, 25);
final View v1 = createTestViewInActivity(activity1, viewBounds);
+ final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay();
mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true));
assertSameElementsEventually(Arrays.asList(viewBounds),
() -> getKeepClearRectsForActivity(activity1));
@@ -438,8 +441,12 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
mWmState.assertVisibility(activity2.getComponentName(), true);
// Since both activities are fullscreen, WM only takes the keep clear areas from the top one
- assertSameElementsEventually(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS,
- activity2.getComponentName()), () -> getKeepClearRectsOnDefaultDisplay());
+ final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>();
+ expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay);
+ expectedRectsOnDisplay.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS,
+ activity2.getComponentName()));
+ assertSameElementsEventually(expectedRectsOnDisplay,
+ () -> getKeepClearRectsOnDefaultDisplay());
}
@Test
@@ -449,15 +456,24 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
translucentTestSession.launchTestActivityOnDisplaySync(
TranslucentTestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity1 = translucentTestSession.getActivity();
-
final Rect viewBounds = new Rect(0, 0, 25, 25);
final View v1 = createTestViewInActivity(activity1, viewBounds);
+ final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay();
translucentTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true));
- assertSameElementsEventually(getRectsInScreenSpace(Arrays.asList(viewBounds),
- activity1.getComponentName()), () -> getKeepClearRectsOnDefaultDisplay());
+ // Add keep-clear rects in the activity
+ final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>();
+ expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay);
+ expectedRectsOnDisplay.addAll(getRectsInScreenSpace(Arrays.asList(viewBounds),
+ activity1.getComponentName()));
+ assertSameElementsEventually(expectedRectsOnDisplay,
+ () -> getKeepClearRectsOnDefaultDisplay());
+
+ // Start an opaque activity on top
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity2 = mTestSession.getActivity();
+
+ // Add keep-clear rects in the opaque activity
final View v2 = createTestViewInActivity(activity2);
mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
@@ -466,8 +482,13 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
mWmState.waitAndAssertVisibilityGone(activity1.getComponentName());
mWmState.assertVisibility(activity2.getComponentName(), true);
- assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
- () -> getKeepClearRectsForActivity(activity2));
+ // Only the opaque activity's keep-clear areas should be reported on the display
+ expectedRectsOnDisplay.clear();
+ expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay);
+ expectedRectsOnDisplay.addAll(getRectsInScreenSpace(
+ TEST_KEEP_CLEAR_RECTS, activity2.getComponentName()));
+ assertSameElementsEventually(expectedRectsOnDisplay,
+ () -> getKeepClearRectsOnDefaultDisplay());
}
@Test
@@ -475,30 +496,15 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
assumeTrue("Skipping test: no split multi-window support",
supportsSplitScreenMultiWindow());
- final LaunchActivityBuilder activityBuilder1 = getLaunchActivityBuilder()
- .setUseInstrumentation()
- .setIntentExtra(extra -> {
- extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS,
- new ArrayList(TEST_KEEP_CLEAR_RECTS));
- })
- .setTargetActivity(KEEP_CLEAR_RECTS_ACTIVITY);
+ startKeepClearActivitiesInSplitscreen(KEEP_CLEAR_RECTS_ACTIVITY,
+ KEEP_CLEAR_RECTS_ACTIVITY2, Collections.emptyList(), Collections.emptyList());
+ final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay();
- final LaunchActivityBuilder activityBuilder2 = getLaunchActivityBuilder()
- .setUseInstrumentation()
- .setIntentExtra(extra -> {
- extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS,
- new ArrayList(TEST_KEEP_CLEAR_RECTS_2));
- })
- .setTargetActivity(KEEP_CLEAR_RECTS_ACTIVITY2);
+ removeRootTask(mWmState.getTaskByActivity(KEEP_CLEAR_RECTS_ACTIVITY).mTaskId);
+ removeRootTask(mWmState.getTaskByActivity(KEEP_CLEAR_RECTS_ACTIVITY2).mTaskId);
- launchActivitiesInSplitScreen(activityBuilder1, activityBuilder2);
-
- waitAndAssertResumedActivity(KEEP_CLEAR_RECTS_ACTIVITY, KEEP_CLEAR_RECTS_ACTIVITY
- + " must be resumed");
- waitAndAssertResumedActivity(KEEP_CLEAR_RECTS_ACTIVITY2, KEEP_CLEAR_RECTS_ACTIVITY2
- + " must be resumed");
- mWmState.assertVisibility(KEEP_CLEAR_RECTS_ACTIVITY, true);
- mWmState.assertVisibility(KEEP_CLEAR_RECTS_ACTIVITY2, true);
+ startKeepClearActivitiesInSplitscreen(KEEP_CLEAR_RECTS_ACTIVITY,
+ KEEP_CLEAR_RECTS_ACTIVITY2, TEST_KEEP_CLEAR_RECTS, TEST_KEEP_CLEAR_RECTS_2);
assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
() -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY));
@@ -506,11 +512,38 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
() -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY2));
final List<Rect> expected = new ArrayList();
+ expected.addAll(prevKeepClearRectsOnDisplay);
expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, KEEP_CLEAR_RECTS_ACTIVITY));
expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS_2, KEEP_CLEAR_RECTS_ACTIVITY2));
assertSameElementsEventually(expected, () -> getKeepClearRectsOnDefaultDisplay());
}
+ private void startKeepClearActivitiesInSplitscreen(ComponentName activity1,
+ ComponentName activity2, List<Rect> keepClearRects1, List<Rect> keepClearRects2) {
+ final LaunchActivityBuilder activityBuilder1 = getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setTargetActivity(activity1)
+ .setIntentExtra(extra -> {
+ extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS,
+ new ArrayList(keepClearRects1));
+ });
+
+ final LaunchActivityBuilder activityBuilder2 = getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setTargetActivity(activity2)
+ .setIntentExtra(extra -> {
+ extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS,
+ new ArrayList(keepClearRects2));
+ });
+
+ launchActivitiesInSplitScreen(activityBuilder1, activityBuilder2);
+
+ waitAndAssertResumedActivity(activity1, activity1 + " must be resumed");
+ waitAndAssertResumedActivity(activity2, activity2 + " must be resumed");
+ mWmState.assertVisibility(activity1, true);
+ mWmState.assertVisibility(activity2, true);
+ }
+
@Test
public void testUnrestrictedKeepClearRects() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
@@ -547,6 +580,7 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
mTestSession.runOnMainSyncAndWait(() -> {
activity.addView(newView, params);
});
+ waitForIdle();
return newView;
}
@@ -607,7 +641,8 @@ public class KeepClearRectsTests extends WindowManagerTestBase {
private static <T> void assertSameElementsEventually(List<T> expected, Callable<List<T>> actual)
throws Exception {
- PollingCheck.check("Lists do not have the same elements.",
+ PollingCheck.check("Lists do not have the same elements."
+ + "Expected=" + expected + ", actual=" + actual.call(),
SAME_ELEMENT_ASSERTION_TIMEOUT,
() -> hasSameElements(expected, actual.call()));
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
index c39aaa2ced6..cbc40261c66 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
@@ -89,6 +89,7 @@ public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
// TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
// in immersive mode
assumeFalse(isCar());
+ assumeFalse(isWatch());
final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
new Intent().putExtra(EXTRA_ORIENTATION, orientation));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SnapshotTaskTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SnapshotTaskTests.java
index 59a1a2bcccd..198e4b344c5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SnapshotTaskTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SnapshotTaskTests.java
@@ -17,6 +17,7 @@
package android.server.wm;
import static android.server.wm.WindowManagerTestBase.startActivity;
+import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -85,6 +86,9 @@ public class SnapshotTaskTests extends ActivityManagerTestBase {
@Test
public void testSetDisablePreviewScreenshots() throws Exception {
+ final View decor = mActivity.getWindow().getDecorView();
+ final int captionBarHeight = decor.getRootWindowInsets().getInsets(captionBar()).top;
+
BitmapPixelChecker pixelChecker = new BitmapPixelChecker(PixelColor.RED);
int retries = 0;
@@ -93,7 +97,8 @@ public class SnapshotTaskTests extends ActivityManagerTestBase {
Bitmap bitmap = mWindowManager.snapshotTaskForRecents(mActivity.getTaskId());
if (bitmap != null) {
int expectedMatching =
- bitmap.getWidth() * bitmap.getHeight() - MATCHING_PIXEL_MISMATCH_ALLOWED;
+ bitmap.getWidth() * bitmap.getHeight() - MATCHING_PIXEL_MISMATCH_ALLOWED
+ - (captionBarHeight * decor.getWidth());
Rect boundToCheck = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
int matchingPixels = pixelChecker.getNumMatchingPixels(bitmap, boundToCheck);
matchesPixels = matchingPixels >= expectedMatching;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
index cfbf89edbc8..87c683e930c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.server.wm.MockImeHelper.createManagedMockImeSession;
import static android.view.SurfaceControlViewHost.SurfacePackage;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -32,6 +33,7 @@ import static org.junit.Assume.assumeTrue;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ComponentName;
@@ -66,6 +68,7 @@ import android.widget.FrameLayout;
import android.widget.PopupWindow;
import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ActivityScenario;
import androidx.test.filters.FlakyTest;
import androidx.test.rule.ActivityTestRule;
@@ -96,6 +99,8 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
private final ActivityTestRule<ConfigChangeHandlingActivity> mActivityRule =
new ActivityTestRule<>(ConfigChangeHandlingActivity.class);
+ private ActivityScenario<ConfigChangeHandlingActivity> mScenario;
+
private Instrumentation mInstrumentation;
private Activity mActivity;
private SurfaceView mSurfaceView;
@@ -919,6 +924,19 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
@Test
public void testEmbeddedViewReceivesInputOnBottom() throws Throwable {
+ // Close the activity that was launched by setup
+ mActivityRule.finishActivity();
+
+ // Launch activity in fullscreen windowing mode
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(mInstrumentation.getTargetContext(), ConfigChangeHandlingActivity.class);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mScenario = ActivityScenario.launch(intent, options.toBundle());
+ mScenario.onActivity(activity -> {
+ mActivity = activity;
+ });
+
mEmbeddedView = new Button(mActivity);
mEmbeddedView.setOnClickListener((View v) -> {
mClicked = true;
@@ -929,7 +947,7 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
waitUntilEmbeddedViewDrawn();
// We should receive no input until we punch a hole
- CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mSurfaceView);
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, null, mSurfaceView);
mInstrumentation.waitForIdleSync();
assertFalse(mClicked);
@@ -949,7 +967,7 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
// operations
waitForTouchableRegionChanged(originalRegion);
- CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mSurfaceView);
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, null, mSurfaceView);
mInstrumentation.waitForIdleSync();
assertTrue(mClicked);
}
@@ -977,6 +995,19 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
@Test
public void testHostInputTokenAllowsObscuredTouches() throws Throwable {
+ // Close the activity that was launched by setup
+ mActivityRule.finishActivity();
+
+ // Launch activity in fullscreen windowing mode
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(mInstrumentation.getTargetContext(), ConfigChangeHandlingActivity.class);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mScenario = ActivityScenario.launch(intent, options.toBundle());
+ mScenario.onActivity(activity -> {
+ mActivity = activity;
+ });
+
SurfaceControlViewHost.SurfacePackage p = null;
mTestService = getService();
@@ -987,7 +1018,7 @@ public class SurfaceControlViewHostTests extends ActivityManagerTestBase impleme
mSurfaceView.getRootSurfaceControl().setTouchableRegion(new Region());
});
mInstrumentation.waitForIdleSync();
- CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mSurfaceView);
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, null, mSurfaceView);
mInstrumentation.waitForIdleSync();
assertTrue(mTestService.getViewIsTouchedAndObscured());
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
index 6b8be2d2f12..7a4c54345a9 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
@@ -60,7 +60,7 @@ public class UnsupportedErrorDialogTests extends ActivityManagerTestBase {
resetAppErrors();
}
- /** Make sure the developer options apply correctly leading to the dialog being shown. */
+ /** Make sure the developer option applies correctly leading to the dialog being shown. */
@Test
public void testDevSettingOverride() {
try (SettingsSession<Integer> devDialogShow =
@@ -71,16 +71,6 @@ public class UnsupportedErrorDialogTests extends ActivityManagerTestBase {
secureIntSession(Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION)) {
// set developer setting to show dialogs anyway
devDialogShow.set(1);
-
- // enable only the regular option for showing the crash dialog after the first crash
- showOnFirstCrash.set(1);
- showOnFirstCrashDev.set(0);
- launchActivityNoWait(Components.CRASHING_ACTIVITY);
- findCrashDialogAndCloseApp();
- ensureActivityNotFocused(Components.CRASHING_ACTIVITY);
-
- resetAppErrors();
-
// enable only the dev option for showing the crash dialog after the first crash
showOnFirstCrash.set(0);
showOnFirstCrashDev.set(1);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index e73ae81999d..7bfc7cd506a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -307,6 +307,7 @@ public class WindowInputTests {
TAPPING_TARGET_WINDOW_SIZE);
// Any opacity higher than this would make InputDispatcher block the touch
params.alpha = mInputManager.getMaximumObscuringOpacityForTouch();
+ params.setFitInsetsTypes(0);
intent.putExtra(EXTRA_LAYOUT_PARAMS, params);
mActivity.startForegroundService(intent);
});
@@ -361,6 +362,7 @@ public class WindowInputTests {
placeWindowAtLayoutCenter(params, TAPPING_TARGET_WINDOW_SIZE,
viewOnScreenLocation[0], viewOnScreenLocation[1],
TAPPING_TARGET_WINDOW_SIZE);
+ params.setFitInsetsTypes(0);
intent.putExtra(EXTRA_LAYOUT_PARAMS, params);
mActivity.startForegroundService(intent);
});
@@ -462,6 +464,7 @@ public class WindowInputTests {
placeWindowAtLayoutCenter(params, TAPPING_TARGET_WINDOW_SIZE,
viewOnScreenLocation[0], viewOnScreenLocation[1],
TAPPING_TARGET_WINDOW_SIZE);
+ params.setFitInsetsTypes(0);
intent.putExtra(EXTRA_LAYOUT_PARAMS, params);
mActivity.startForegroundService(intent);
});
@@ -517,6 +520,7 @@ public class WindowInputTests {
viewOnScreenLocation[0], viewOnScreenLocation[1], TAPPING_TARGET_WINDOW_SIZE);
// Move it off the touch path (center) but still overlap with window above
params.y += PARTIAL_OBSCURING_WINDOW_SIZE;
+ params.setFitInsetsTypes(0);
intent.putExtra(EXTRA_LAYOUT_PARAMS, params);
mActivity.startForegroundService(intent);
});
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index 1d9164d78b2..0281f55a71d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -246,6 +246,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_andCancel() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
runOnUiThread(() -> {
setupAnimationListener();
@@ -266,6 +268,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Test
public void testControl_andImmediatelyCancel() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
runOnUiThread(() -> {
setupAnimationListener();
@@ -283,6 +287,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_immediately_show() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
setVisibilityAndWait(mType, false);
@@ -306,6 +312,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_immediately_hide() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
setVisibilityAndWait(mType, true);
@@ -329,6 +337,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_transition_show() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
setVisibilityAndWait(mType, false);
@@ -350,6 +360,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_transition_hide() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
setVisibilityAndWait(mType, true);
@@ -371,6 +383,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_transition_show_interpolator() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
mInterpolator = new DecelerateInterpolator();
setVisibilityAndWait(mType, false);
@@ -393,6 +407,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Presubmit
@Test
public void testControl_transition_hide_interpolator() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
mInterpolator = new AccelerateInterpolator();
setVisibilityAndWait(mType, true);
@@ -414,6 +430,8 @@ public class WindowInsetsAnimationControllerTests extends WindowManagerTestBase
@Test
public void testControl_andLoseControl() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars() && mType != ime());
+
retryIfCancelled(() -> {
mInterpolator = new AccelerateInterpolator();
setVisibilityAndWait(mType, true);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 86ec2fa236c..87c0fc8bb27 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -29,6 +29,7 @@ import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
@@ -70,6 +71,7 @@ public class WindowInsetsAnimationTests extends WindowInsetsAnimationTestBase {
WINDOWING_MODE_FULLSCREEN);
mRootView = mActivity.getWindow().getDecorView();
assumeTrue(hasWindowInsets(mRootView, systemBars()));
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
}
@Test
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 91916b169b3..4a76d928c9d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -116,6 +116,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testHide() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -134,6 +136,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testShow() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -181,6 +185,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testTopAppHidesStatusBarByMethod() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -190,6 +196,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testTopAppHidesStatusBarByWindowFlag() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivity(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -199,6 +207,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testTopAppHidesStatusBarBySystemUiFlag() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivity(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -291,6 +301,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testSetSystemBarsBehavior_default() throws InterruptedException {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -317,6 +329,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testSetSystemBarsBehavior_showTransientBarsBySwipe() throws InterruptedException {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivity(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -398,6 +412,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testSystemUiVisibilityCallbackCausedByInsets() {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivity(TestActivity.class);
final View controlTarget = activity.getWindow().getDecorView();
final int[] targetSysUiVis = new int[1];
@@ -425,6 +441,7 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
private void testSysUiVisCallbackCausedByInsets(int insetsType, int sysUiFlag, View target,
int[] targetSysUiVis, int[] nonTargetSysUiVis) {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
if (target.getRootWindowInsets().isVisible(insetsType)) {
// Controlled by methods
@@ -453,6 +470,11 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
public void testSystemUiVisibilityCallbackCausedByAppearance() {
final TestActivity activity = startActivity(TestActivity.class);
final View controlTarget = activity.getWindow().getDecorView();
+
+ // Assume we have at least one visible system bar.
+ assumeTrue(controlTarget.getRootWindowInsets().isVisible(statusBars()) ||
+ controlTarget.getRootWindowInsets().isVisible(navigationBars()));
+
final int[] targetSysUiVis = new int[1];
getInstrumentation().runOnMainSync(() -> {
controlTarget.setOnSystemUiVisibilityChangeListener(
@@ -468,6 +490,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testSetSystemUiVisibilityAfterCleared_showBarsBySwipe() throws Exception {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -527,6 +551,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testSetSystemUiVisibilityAfterCleared_showBarsByApp() throws Exception {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestActivity activity = startActivityInWindowingModeFullScreen(TestActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -567,6 +593,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testHideOnCreate() throws Exception {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestHideOnCreateActivity activity =
startActivityInWindowingModeFullScreen(TestHideOnCreateActivity.class);
final View rootView = activity.getWindow().getDecorView();
@@ -654,6 +682,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testInsetsDispatch() throws Exception {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
// Start an activity which hides system bars in fullscreen mode,
// otherwise, it might not be able to hide system bars in other windowing modes.
final TestHideOnCreateActivity activity = startActivityInWindowingModeFullScreen(
@@ -688,6 +718,8 @@ public class WindowInsetsControllerTests extends WindowManagerTestBase {
@Test
public void testWindowInsetsController_availableAfterAddView() throws Exception {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
final TestHideOnCreateActivity activity =
startActivityInWindowingModeFullScreen(TestHideOnCreateActivity.class);
final View rootView = activity.getWindow().getDecorView();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
index 806cee588e7..b0c2a12cff1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
@@ -199,6 +199,8 @@ public class WindowInsetsPolicyTest extends ActivityManagerTestBase {
@Test
public void testImmersiveFullscreenHidesSystemBars() throws Throwable {
+ assumeFalse(isCar() && remoteInsetsControllerControlsSystemBars());
+
// Run the test twice, because the issue that shows system bars even in the immersive mode,
// happens at the 2nd try.
for (int i = 1; i <= 2; ++i) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
index f895e4f8a1a..f9211904bf4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
@@ -240,6 +240,9 @@ public class ActivityLifecyclePipTests extends ActivityLifecycleClientTestBase {
assertEmptySequence(PipActivity.class, getTransitionLog(),
"launchBelow");
+ // Set secondary split as launch root
+ mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
+
// Launch second activity to side
getTransitionLog().clear();
new Launcher(SecondActivity.class)
@@ -264,6 +267,9 @@ public class ActivityLifecyclePipTests extends ActivityLifecycleClientTestBase {
// Enter split screen
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
+ // Set secondary split as launch root
+ mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
+
// Launch second activity to side
final Activity secondActivity = new Launcher(SecondActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 46081611198..bfb3e88dce2 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -1999,6 +1999,7 @@ public abstract class ActivityManagerTestBase {
static final int EQUALS = 1;
static final int GREATER_THAN = 2;
static final int LESS_THAN = 3;
+ static final int GREATER_THAN_OR_EQUALS = 4;
final T mEvent;
final int mRule;
@@ -2022,6 +2023,9 @@ public abstract class ActivityManagerTestBase {
case LESS_THAN:
mMessage = event + " must be less than " + count;
break;
+ case GREATER_THAN_OR_EQUALS:
+ mMessage = event + " must be greater than (or equals to) " + count;
+ break;
default:
mMessage = "Don't care";
}
@@ -2039,6 +2043,8 @@ public abstract class ActivityManagerTestBase {
return value > mCount;
case LESS_THAN:
return value < mCount;
+ case GREATER_THAN_OR_EQUALS:
+ return value >= mCount;
default:
}
throw new RuntimeException("Unknown CountSpec rule");
diff --git a/tests/media/src/android/mediav2/cts/CodecInfoTest.java b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
index e42835e2c9f..9ced5527653 100644
--- a/tests/media/src/android/mediav2/cts/CodecInfoTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecInfoTest.java
@@ -28,6 +28,7 @@ import android.view.Display;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.MediaUtils;
import org.junit.Assert;
import org.junit.Assume;
@@ -168,18 +169,37 @@ public class CodecInfoTest {
IntStream.of(caps.colorFormats)
.noneMatch(x -> x == COLOR_FormatSurface));
}
+ }
- // For devices launching with Android T, if a codec supports an HDR profile and device
- // supports HDR display, it must advertise P010 support
+ /** For devices launching with Android T or higher, if a codec supports an HDR profile and
+ * device supports HDR display, it must support COLOR_FormatYUVP010 as a video decoder output
+ * format. For TVs, this requirement is optional.
+ */
+ @Test
+ public void testP010SupportForHDRDisplay() {
+ Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
+ MediaCodecInfo.CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mMediaType);
int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
if (FIRST_SDK_IS_AT_LEAST_T && 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 + "," +
- " but does not support COLOR_FormatYUVP010",
- IntStream.of(caps.colorFormats)
- .noneMatch(x -> x == COLOR_FormatYUVP010));
+ if (MediaUtils.isTv()) {
+ // Some TV devices support HDR10 display with VO instead of GPU. In this
+ // case, skip checking P010 on TV devices.
+ Assume.assumeFalse(mCodecInfo.getName() + " supports HDR profile "
+ + pl.profile + ","
+ + " but does not support COLOR_FormatYUVP010."
+ + " Skip checking on TV device",
+ IntStream.of(caps.colorFormats)
+ .noneMatch(x -> x == COLOR_FormatYUVP010));
+ } else {
+ assertFalse(mCodecInfo.getName() + " supports HDR profile "
+ + pl.profile + "," +
+ " but does not support COLOR_FormatYUVP010",
+ IntStream.of(caps.colorFormats)
+ .noneMatch(x -> x == COLOR_FormatYUVP010));
+ }
}
}
}
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index c196d6e492b..3867f04e71e 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -128,12 +128,11 @@ public class EncoderProfileLevelTest extends CodecEncoderTestBase {
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 3000000, 704, 576, 30},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 8000000, 720, 576, 30},
- // TODO (b/151430764)
- /*{MediaFormat.MIMETYPE_VIDEO_VP9, 200000, 256, 144, 15},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, 200000, 256, 144, 15},
{MediaFormat.MIMETYPE_VIDEO_VP9, 8000000, 384, 192, 30},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1800000, 480, 256, 30},
{MediaFormat.MIMETYPE_VIDEO_VP9, 3600000, 640, 384, 30},
- {MediaFormat.MIMETYPE_VIDEO_VP9, 7200000, 1080, 512, 30},*/
+ {MediaFormat.MIMETYPE_VIDEO_VP9, 7200000, 1080, 512, 30},
{MediaFormat.MIMETYPE_VIDEO_VP9, 12000000, 1280, 768, 30},
{MediaFormat.MIMETYPE_VIDEO_VP9, 18000000, 2048, 1088, 30},
{MediaFormat.MIMETYPE_VIDEO_VP9, 30000000, 2048, 1088, 60},
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index e9067208b94..ed80e302d4e 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -1980,11 +1980,13 @@ public class UsageStatsTest {
final long startTime = System.currentTimeMillis();
launchTestActivity(TEST_APP2_PKG, TEST_APP2_CLASS_PIP);
- SystemClock.sleep(500);
+ final long sleepTime1 = 500;
+ SystemClock.sleep(sleepTime1);
// TEST_APP_PKG should take focus, pausing the TEST_APP2_CLASS_PIP activity.
launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
- SystemClock.sleep(500);
+ final long sleepTime2 = 500;
+ SystemClock.sleep(sleepTime2);
mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
WindowManagerState.STATE_PAUSED);
@@ -2027,6 +2029,13 @@ public class UsageStatsTest {
assertEquals("Unexpected number of activity resumes", 1, resumes);
assertEquals("Unexpected number of activity pauses", 1, pauses);
assertEquals("Unexpected number of activity stops", 0, stops);
+
+ final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
+ startTime, endTime);
+ final UsageStats stats = map.get(TEST_APP2_PKG);
+ assertNotNull(stats);
+ final long totalTimeVisible = stats.getTotalTimeVisible();
+ assertLessThan(sleepTime1 + sleepTime2, totalTimeVisible);
}
@AppModeFull(reason = "No usage events access in instant apps")
diff --git a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSelfManagedTest.kt b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSelfManagedTest.kt
index ca63dd220ea..a37ced0564f 100644
--- a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSelfManagedTest.kt
+++ b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSelfManagedTest.kt
@@ -8,6 +8,7 @@ import android.companion.cts.common.CompanionActivity
import android.companion.cts.common.RecordingCallback.OnAssociationCreated
import android.content.Intent
import android.platform.test.annotations.AppModeFull
+import com.android.compatibility.common.util.FeatureUtil
import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
@@ -34,6 +35,7 @@ class AssociationEndToEndSelfManagedTest(
override fun setUp() {
super.setUp()
+ assumeFalse(FeatureUtil.isWatch())
// TODO(b/211602270): Add support for WATCH and "null" profiles in the
// confirmation UI (the "self-managed" flow variant).
assumeFalse(profile == null)
diff --git a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSingleDeviceTest.kt b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSingleDeviceTest.kt
index 92e1b49fd17..d1cee82224c 100644
--- a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSingleDeviceTest.kt
+++ b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndSingleDeviceTest.kt
@@ -5,6 +5,7 @@ import android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION
import android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER
import android.platform.test.annotations.AppModeFull
+import com.android.compatibility.common.util.FeatureUtil
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -28,6 +29,7 @@ class AssociationEndToEndSingleDeviceTest(
override fun setUp() {
super.setUp()
+ assumeFalse(FeatureUtil.isWatch())
// TODO(b/211722613): Add support for DEVICE_PROFILE_APP_STREAMING
// DEVICE_PROFILE_COMPUTER and DEVICE_PROFILE_AUTOMOTIVE_PROJECTION
// profiles in the confirmation UI (the "single_device" flow variant).
diff --git a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndTest.kt b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndTest.kt
index ffc52eb7708..8da92e64199 100644
--- a/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndTest.kt
+++ b/tests/tests/companion/uiautomation/src/android/companion/cts/uiautomation/AssociationEndToEndTest.kt
@@ -20,6 +20,7 @@ import android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING
import android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION
import android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER
import android.platform.test.annotations.AppModeFull
+import com.android.compatibility.common.util.FeatureUtil
import org.junit.Assume.assumeFalse
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,6 +42,7 @@ class AssociationEndToEndTest(
override fun setUp() {
super.setUp()
+ assumeFalse(FeatureUtil.isWatch())
// TODO(b/211590680): Add support for APP_STREAMING, AUTOMOTIVE_PROJECTION and COMPUTER
// in the confirmation UI (the "multiple devices" flow variant).
assumeFalse(profile == DEVICE_PROFILE_COMPUTER)
diff --git a/tests/tests/content/src/android/content/pm/cts/FeatureTest.java b/tests/tests/content/src/android/content/pm/cts/FeatureTest.java
index 68edc76c597..58a40117df6 100644
--- a/tests/tests/content/src/android/content/pm/cts/FeatureTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/FeatureTest.java
@@ -72,7 +72,7 @@ public class FeatureTest extends AndroidTestCase {
}
// Managed profiles only required for handheld devices
- if (!isHandheldDevice()) {
+ if (!isHandheldOrTabletDevice()) {
return;
}
@@ -91,12 +91,20 @@ public class FeatureTest extends AndroidTestCase {
}
/**
- * The CDD defines a handheld device as one that has a battery and a screen size between
- * 2.5 and 8 inches.
+ * The CDD defines:
+ * - A handheld device as one that has a battery and a screen size between 2.5 and 8 inches.
+ * - A tablet device as one that has a battery and a screen size between 7 and 18 inches.
*/
- private boolean isHandheldDevice() throws Exception {
+ private boolean isHandheldOrTabletDevice() throws Exception {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_EMBEDDED)) {
+ return false;
+ }
+
double screenInches = getScreenSizeInInches();
- return deviceHasBattery() && screenInches >= 2.5 && screenInches <= 8.0;
+ return deviceHasBattery() && screenInches >= 2.5 && screenInches <= 18.0;
}
private boolean deviceHasBattery() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index ef44528cbff..852223c212c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -1010,7 +1010,7 @@ public class BitmapFactoryTest {
@Test
@RequiresDevice
- public void testDecode10BitHEIFTo10BitBitmap() {
+ public void testDecode10BitHEIF() {
assumeTrue(
"Test needs Android T.", ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU));
assumeTrue(
@@ -1018,13 +1018,23 @@ public class BitmapFactoryTest {
SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
+ Config preferredConfig = Config.RGBA_1010102;
+
+ // For TVs, even if the device advertises that 10 bits profile is supported, the output
+ // format might not be CPU readable, but can still be displayed. When the TV device is
+ // not capable to decode to YUVP010 format, it should be able to fall back to decode to
+ // RGB_565 format.
+ if (MediaUtils.isTv() && !hasHEVCDecoderSupportsYUVP010()) {
+ preferredConfig = Config.RGB_565;
+ }
+
BitmapFactory.Options opt = new BitmapFactory.Options();
- opt.inPreferredConfig = Config.RGBA_1010102;
+ opt.inPreferredConfig = preferredConfig;
Bitmap bm = BitmapFactory.decodeStream(obtainInputStream(R.raw.heifimage_10bit), null, opt);
assertNotNull(bm);
assertEquals(4096, bm.getWidth());
assertEquals(3072, bm.getHeight());
- assertEquals(Config.RGBA_1010102, bm.getConfig());
+ assertEquals(preferredConfig, bm.getConfig());
}
@Test
@@ -1037,6 +1047,16 @@ public class BitmapFactoryTest {
SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
+ // For TVs, even if the device advertises that 10 bits profile is supported, the output
+ // format might not be CPU readable, but can still be displayed, and only when the TV
+ // is capable to decode to YUVP010 format, the image can be converted into RGBA_1010102,
+ // and this test can continue.
+ if (MediaUtils.isTv()) {
+ assumeTrue(
+ "The TV is unable to decode to RGBA_1010102 format, skip the test",
+ hasHEVCDecoderSupportsYUVP010());
+ }
+
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Config.ARGB_8888;
Bitmap bm1 =
@@ -1113,4 +1133,26 @@ public class BitmapFactoryTest {
}
return true;
}
+
+ private static boolean hasHEVCDecoderSupportsYUVP010() {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) {
+ if (mediaCodecInfo.isEncoder()) {
+ continue;
+ }
+ for (String mediaType : mediaCodecInfo.getSupportedTypes()) {
+ if (mediaType.equalsIgnoreCase("video/hevc")) {
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ mediaCodecInfo.getCapabilitiesForType(mediaType);
+ for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) {
+ if (codecCapabilities.colorFormats[i]
+ == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index b6689d87f54..8bb2a3c72c7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -252,6 +252,16 @@ public class ImageDecoderTest {
SystemProperties.getInt("ro.vndk.version", 0) >= Build.VERSION_CODES.TIRAMISU);
assumeTrue("No 10-bit HEVC decoder, skip the test.", has10BitHEVCDecoder());
+ // For TVs, even if the device advertises that 10 bits profile is supported, the output
+ // format might not be CPU readable, but can still be displayed, and only when the TV
+ // is capable to decode to YUVP010 format, the image can be converted into RGBA_1010102,
+ // and this test can continue.
+ if (MediaUtils.isTv()) {
+ assumeTrue(
+ "The TV is unable to decode to YUVP010 format, skip the test",
+ hasHEVCDecoderSupportsYUVP010());
+ }
+
try {
ImageDecoder.Source src = ImageDecoder
.createSource(getResources(), R.raw.heifimage_10bit);
@@ -2789,4 +2799,26 @@ public class ImageDecoderTest {
}
return true;
}
+
+ private static boolean hasHEVCDecoderSupportsYUVP010() {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ for (MediaCodecInfo mediaCodecInfo : codecList.getCodecInfos()) {
+ if (mediaCodecInfo.isEncoder()) {
+ continue;
+ }
+ for (String mediaType : mediaCodecInfo.getSupportedTypes()) {
+ if (mediaType.equalsIgnoreCase("video/hevc")) {
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ mediaCodecInfo.getCapabilitiesForType(mediaType);
+ for (int i = 0; i < codecCapabilities.colorFormats.length; ++i) {
+ if (codecCapabilities.colorFormats[i]
+ == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 56dd1b0f561..bf2e941bfa5 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -16,11 +16,13 @@
package android.keystore.cts;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -37,6 +39,13 @@ import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.bedstead.nene.annotations.Nullable;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
@@ -63,6 +72,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
@@ -78,11 +88,6 @@ import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.security.auth.x500.X500Principal;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
public class AndroidKeyStoreTest {
private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
@@ -823,6 +828,12 @@ public class AndroidKeyStoreTest {
expectedAliases.length, count);
}
+ private void deleteEntryIfNotNull(@Nullable String alias) throws Exception {
+ if (alias != null) {
+ mKeyStore.deleteEntry(alias);
+ }
+ }
+
@Test
public void testKeyStore_Aliases_Unencrypted_Success() throws Exception {
mKeyStore.load(null, null);
@@ -2161,8 +2172,9 @@ public class AndroidKeyStoreTest {
PrivateKey privateKey3 = generatePrivateKey("RSA", FAKE_RSA_KEY_1);
final int MAX_NUMBER_OF_KEYS = 2500;
- final String ALIAS_PREFIX = "test_large_number_of_rsa_keys_";
+ final StringBuilder aliasPrefix = new StringBuilder("test_large_number_of_rsa_keys_");
int keyCount = 0;
+ String entryName2 = null;
mKeyStore.load(null);
try {
@@ -2175,11 +2187,12 @@ public class AndroidKeyStoreTest {
new KeyStore.PrivateKeyEntry(privateKey1, new Certificate[] {cert1}),
protectionParams);
- keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, ALIAS_PREFIX,
- new PrivateKeyEntry(privateKey3, new Certificate[] {cert3}), protectionParams);
+ keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, aliasPrefix,
+ new PrivateKeyEntry(privateKey3, new Certificate[] {cert3}),
+ protectionParams);
keyCount++;
- String entryName2 = "test" + keyCount;
+ entryName2 = "test" + keyCount;
mKeyStore.setEntry(entryName2,
new KeyStore.PrivateKeyEntry(privateKey2, new Certificate[] {cert2}),
protectionParams);
@@ -2206,7 +2219,9 @@ public class AndroidKeyStoreTest {
sig.update(message);
assertTrue(sig.verify(signature));
} finally {
- deleteManyTestKeys(keyCount, ALIAS_PREFIX);
+ mKeyStore.deleteEntry(entryName1);
+ deleteEntryIfNotNull(entryName2);
+ deleteManyTestKeys(keyCount, aliasPrefix);
}
}
@@ -2235,8 +2250,9 @@ public class AndroidKeyStoreTest {
PrivateKey privateKey3 = generatePrivateKey("EC", FAKE_EC_KEY_1);
final int MAX_NUMBER_OF_KEYS = 2500;
- final String ALIAS_PREFIX = "test_large_number_of_ec_keys_";
+ final StringBuilder aliasPrefix = new StringBuilder("test_large_number_of_ec_keys_");
int keyCount = 0;
+ String entryName2 = null;
mKeyStore.load(null);
try {
@@ -2248,12 +2264,12 @@ public class AndroidKeyStoreTest {
new KeyStore.PrivateKeyEntry(privateKey1, new Certificate[] {cert1}),
protectionParams);
- keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, ALIAS_PREFIX,
+ keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, aliasPrefix,
new KeyStore.PrivateKeyEntry(privateKey3, new Certificate[] {cert3}),
protectionParams);
keyCount++;
- String entryName2 = "test" + keyCount;
+ entryName2 = "test" + keyCount;
mKeyStore.setEntry(entryName2,
new KeyStore.PrivateKeyEntry(privateKey2, new Certificate[] {cert2}),
protectionParams);
@@ -2280,7 +2296,9 @@ public class AndroidKeyStoreTest {
sig.update(message);
assertTrue(sig.verify(signature));
} finally {
- deleteManyTestKeys(keyCount, ALIAS_PREFIX);
+ mKeyStore.deleteEntry(entryName1);
+ deleteEntryIfNotNull(entryName2);
+ deleteManyTestKeys(keyCount, aliasPrefix);
}
}
@@ -2307,8 +2325,9 @@ public class AndroidKeyStoreTest {
HexEncoding.decode("33333333333333333333777777777777"), "AES");
final int MAX_NUMBER_OF_KEYS = 10000;
- final String ALIAS_PREFIX = "test_large_number_of_aes_keys_";
+ final StringBuilder aliasPrefix = new StringBuilder("test_large_number_of_aes_keys_");
int keyCount = 0;
+ String entryName2 = null;
mKeyStore.load(null);
try {
@@ -2319,11 +2338,11 @@ public class AndroidKeyStoreTest {
.build();
mKeyStore.setEntry(entryName1, new KeyStore.SecretKeyEntry(key1), protectionParams);
- keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, ALIAS_PREFIX,
+ keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, aliasPrefix,
new KeyStore.SecretKeyEntry(key3), protectionParams);
++keyCount;
- String entryName2 = "test" + keyCount;
+ entryName2 = "test" + keyCount;
mKeyStore.setEntry(entryName2, new KeyStore.SecretKeyEntry(key2), protectionParams);
SecretKey keystoreKey2 = (SecretKey) mKeyStore.getKey(entryName2, null);
SecretKey keystoreKey1 = (SecretKey) mKeyStore.getKey(entryName1, null);
@@ -2345,7 +2364,9 @@ public class AndroidKeyStoreTest {
cipher.init(Cipher.DECRYPT_MODE, key2, cipherParams);
assertArrayEquals(plaintext, cipher.doFinal(ciphertext));
} finally {
- deleteManyTestKeys(keyCount, ALIAS_PREFIX);
+ mKeyStore.deleteEntry(entryName1);
+ deleteEntryIfNotNull(entryName2);
+ deleteManyTestKeys(keyCount, aliasPrefix);
}
}
@@ -2374,8 +2395,9 @@ public class AndroidKeyStoreTest {
HexEncoding.decode("33333333333333333333777777777777"), "HmacSHA256");
final int MAX_NUMBER_OF_KEYS = 10000;
- final String ALIAS_PREFIX = "test_large_number_of_hmac_keys_";
+ final StringBuilder aliasPrefix = new StringBuilder("test_large_number_of_hmac_keys_");
int keyCount = 0;
+ String entryName2 = null;
mKeyStore.load(null);
try {
@@ -2384,11 +2406,11 @@ public class AndroidKeyStoreTest {
.build();
mKeyStore.setEntry(entryName1, new KeyStore.SecretKeyEntry(key1), protectionParams);
- keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, ALIAS_PREFIX,
+ keyCount = importKeyManyTimes(MAX_NUMBER_OF_KEYS, aliasPrefix,
new KeyStore.SecretKeyEntry(key3), protectionParams);
keyCount++;
- String entryName2 = "test" + keyCount;
+ entryName2 = "test" + keyCount;
mKeyStore.setEntry(entryName2, new KeyStore.SecretKeyEntry(key2), protectionParams);
SecretKey keystoreKey2 = (SecretKey) mKeyStore.getKey(entryName2, null);
SecretKey keystoreKey1 = (SecretKey) mKeyStore.getKey(entryName1, null);
@@ -2408,7 +2430,9 @@ public class AndroidKeyStoreTest {
"59b57e77e4e2cb36b5c7b84af198ac004327bc549de6931a1b5505372dd8c957"),
mac.doFinal(message));
} finally {
- deleteManyTestKeys(keyCount, ALIAS_PREFIX);
+ mKeyStore.deleteEntry(entryName1);
+ deleteEntryIfNotNull(entryName2);
+ deleteManyTestKeys(keyCount, aliasPrefix);
}
}
@@ -2606,8 +2630,8 @@ public class AndroidKeyStoreTest {
*
* This method is time-bounded
*/
- private int importKeyManyTimes(int numberOfKeys, String aliasPrefix, Entry keyEntry,
- KeyProtection protectionParams)
+ private int importKeyManyTimes(int numberOfKeys, StringBuilder aliasPrefix, Entry keyEntry,
+ KeyProtection protectionParams, boolean isTimeBound)
throws InterruptedException {
TimeBox timeBox = new TimeBox(mMaxImportDuration);
AtomicInteger keyCounter = new AtomicInteger(0);
@@ -2616,7 +2640,7 @@ public class AndroidKeyStoreTest {
threads.add(new Thread(() -> {
// Import key lots of times, under different aliases. Do this until we either run
// out of time or we import the key numberOfKeys times.
- while (!timeBox.isOutOfTime()) {
+ while (!isTimeBound || !timeBox.isOutOfTime()) {
int count = keyCounter.incrementAndGet();
if (count > numberOfKeys) {
// The loop is inherently racy, as multiple threads are simultaneously
@@ -2629,7 +2653,7 @@ public class AndroidKeyStoreTest {
if ((count % 1000) == 0) {
Log.i(TAG, "Imported " + count + " keys");
}
- String entryAlias = aliasPrefix + count;
+ String entryAlias = aliasPrefix.toString() + count;
try {
mKeyStore.setEntry(entryAlias, keyEntry, protectionParams);
} catch (Throwable e) {
@@ -2646,7 +2670,7 @@ public class AndroidKeyStoreTest {
threads.get(i).join();
}
Log.i(TAG, "Imported " + keyCounter.get() + " keys in " + timeBox.elapsed());
- if (keyCounter.get() < MIN_SUPPORTED_KEY_COUNT) {
+ if (keyCounter.get() != numberOfKeys && keyCounter.get() < MIN_SUPPORTED_KEY_COUNT) {
fail("Failed to import " + MIN_SUPPORTED_KEY_COUNT + " keys in "
+ timeBox.elapsed() + ". Imported: " + keyCounter.get() + " keys");
}
@@ -2654,11 +2678,22 @@ public class AndroidKeyStoreTest {
return keyCounter.get();
}
+ private int importKeyManyTimes(int numberOfKeys, StringBuilder aliasPrefix, Entry keyEntry,
+ KeyProtection protectionParams) throws InterruptedException {
+ return importKeyManyTimes(numberOfKeys, aliasPrefix, keyEntry, protectionParams, true);
+ }
+
+ private int importKeyManyTimesWithoutTimeLimit(int numberOfKeys, StringBuilder aliasPrefix,
+ Entry keyEntry,
+ KeyProtection protectionParams) throws InterruptedException {
+ return importKeyManyTimes(numberOfKeys, aliasPrefix, keyEntry, protectionParams, false);
+ }
+
/**
* Delete <code>numberOfKeys</code> keys that follow the pattern "[aliasPrefix][keyCounter]".
* This is done across multiple threads to both increase throughput as well as stress keystore.
*/
- private void deleteManyTestKeys(int numberOfKeys, String aliasPrefix)
+ private void deleteManyTestKeys(int numberOfKeys, StringBuilder aliasPrefix)
throws InterruptedException {
// Clean up Keystore without using KeyStore.aliases() which can't handle this many
// entries.
@@ -2673,8 +2708,9 @@ public class AndroidKeyStoreTest {
if ((key > 0) && ((key % 1000) == 0)) {
Log.i(TAG, "Deleted " + key + " keys");
}
+ String entryAlias = aliasPrefix.toString() + key;
try {
- mKeyStore.deleteEntry("test" + key);
+ mKeyStore.deleteEntry(entryAlias);
} catch (Exception e) {
fail("Unexpected exception in key cleanup: " + e);
}
@@ -2690,4 +2726,114 @@ public class AndroidKeyStoreTest {
}
Log.i(TAG, "Deleted " + numberOfKeys + " keys");
}
+
+ private Set<String> createLargeNumberOfKeyStoreEntryAliases(int numberOfKeys,
+ StringBuilder aliasPrefix)
+ throws Exception {
+ Certificate cert = generateCertificate(FAKE_RSA_USER_1);
+ PrivateKey privateKey = generatePrivateKey("RSA", FAKE_RSA_KEY_1);
+
+ mKeyStore.load(null);
+ KeyProtection protectionParams = new KeyProtection.Builder(
+ KeyProperties.PURPOSE_SIGN)
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build();
+
+ int keyCount = importKeyManyTimesWithoutTimeLimit(numberOfKeys, aliasPrefix,
+ new PrivateKeyEntry(privateKey, new Certificate[]{cert}), protectionParams);
+
+ // Construct expected aliases list.
+ final Set<String> expectedAliases = new HashSet<>(keyCount);
+ for (int count = 1; count <= keyCount; count++) {
+ String entryAlias = aliasPrefix.toString() + count;
+ expectedAliases.add(entryAlias);
+ }
+
+ return expectedAliases;
+ }
+
+ private void importLargeNumberOfKeysValidateAliases(int numberOfKeys, StringBuilder aliasPrefix)
+ throws Exception {
+ Set<String> importedKeyAliases = createLargeNumberOfKeyStoreEntryAliases(numberOfKeys,
+ aliasPrefix);
+ assertThat(importedKeyAliases.size()).isEqualTo(numberOfKeys);
+
+ try {
+ // b/222287335 Currently, limiting Keystore `listEntries` API to return subset of the
+ // Keystore entries to avoid running out of binder buffer space.
+ // To verify that all the imported key aliases are present in Keystore, get the list of
+ // aliases from Keystore, delete the matched aliases from Keystore and imported list of
+ // key aliases, continue this till all the imported key aliases are matched.
+ while (!importedKeyAliases.isEmpty()) {
+ // List the keystore entries aliases until all the imported key aliases are matched.
+ Set<String> aliases = new HashSet<String>(Collections.list(mKeyStore.aliases()));
+
+ // Try to match the aliases with imported key aliases.
+ // Cleanup matching aliases from Keystore and imported key aliases list.
+ for (String alias: aliases) {
+ if (importedKeyAliases.contains(alias)) {
+ mKeyStore.deleteEntry(alias);
+ importedKeyAliases.remove(alias);
+ }
+ }
+ }
+ assertTrue("Failed to match imported keystore entries.",
+ importedKeyAliases.isEmpty());
+ } finally {
+ if (!importedKeyAliases.isEmpty()) {
+ Log.i(TAG, "Final cleanup of imported keys");
+ for (String alias: importedKeyAliases) {
+ mKeyStore.deleteEntry(alias);
+ }
+ }
+ }
+ assertTrue(importedKeyAliases.isEmpty());
+ }
+
+ /**
+ * Create long alias prefix of length 6000 characters.
+ */
+ private StringBuilder createLongAliasPrefix() {
+ char[] prefixChar = new char[6000];
+ Arrays.fill(prefixChar, 'T');
+ StringBuilder prefixAlias = new StringBuilder();
+ prefixAlias.append(prefixChar);
+
+ return prefixAlias;
+ }
+
+ /**
+ * Create large number of Keystore entries with long aliases and try to list aliases of all the
+ * entries in the keystore.
+ */
+ @Test
+ public void testKeyStore_LargeNumberOfLongAliases() throws Exception {
+ final int maxNumberOfKeys = 100;
+
+ importLargeNumberOfKeysValidateAliases(maxNumberOfKeys, createLongAliasPrefix());
+ }
+
+ /**
+ * Create limited number of Keystore entries with long aliases and try to list aliases of all
+ * the entries in the keystore. Test should successfully list all the Keystore entries aliases.
+ */
+ @Test
+ public void testKeyStore_LimitedNumberOfLongAliasesSuccess() throws Exception {
+ final int maxNumberOfKeys = 10;
+ importLargeNumberOfKeysValidateAliases(maxNumberOfKeys, createLongAliasPrefix());
+ }
+
+ /**
+ * Create large number of Keystore entries with short length aliases and try to list aliases of
+ * all the entries in the keystore. Test should successfully list all the Keystore entries
+ * aliases.
+ */
+ @Test
+ public void testKeyStore_LargeNumberShortAliasesSuccess() throws Exception {
+ final int maxNumberOfKeys = 2500;
+ final StringBuilder aliasPrefix = new StringBuilder("test_short_key_alias_");
+
+ importLargeNumberOfKeysValidateAliases(maxNumberOfKeys, aliasPrefix);
+ }
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index e6de05385de..26b3658d974 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -616,16 +616,11 @@ public class CipherTest {
return (pm != null && pm.hasSystemFeature("android.software.leanback_only"));
}
- private boolean hasSecureLockScreen() {
- PackageManager pm = getContext().getPackageManager();
- return (pm != null && pm.hasSystemFeature("android.software.secure_lock_screen"));
- }
-
@Presubmit
@Test
public void testKeyguardLockAndUnlock()
throws Exception {
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
@@ -647,7 +642,7 @@ public class CipherTest {
final boolean isUnlockedDeviceRequired = true;
final boolean isUserAuthRequired = false;
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
@@ -1165,7 +1160,7 @@ public class CipherTest {
final boolean isUnlockedDeviceRequired = false;
final boolean isUserAuthRequired = true;
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 043b5de11cd..99e3d756ff4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -60,6 +60,7 @@ 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.assumeTrue;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -494,6 +495,9 @@ public class KeyAttestationTest {
@Test
public void testEcAttestation_UniqueIdWorksWithCorrectPermission() throws Exception {
+ assumeTrue("Device doesn't have secure lock screen",
+ TestUtils.hasSecureLockScreen(getContext()));
+
String keystoreAlias = "test_key";
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
diff --git a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
index 84e8969007f..b965204fa76 100644
--- a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
@@ -24,8 +24,8 @@ import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.SystemProperties;
import android.security.keystore.KeyGenParameterSpec;
@@ -55,6 +55,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
@@ -76,7 +77,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.security.SecureRandom;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@@ -1140,4 +1140,9 @@ public class TestUtils {
public static boolean isAttestationSupported() {
return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
}
+
+ public static boolean hasSecureLockScreen(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN));
+ }
}
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/AudioManagerTest.java b/tests/tests/media/audio/src/android/media/audio/cts/AudioManagerTest.java
index 5ba8f7e64fa..c9588f45344 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/AudioManagerTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/AudioManagerTest.java
@@ -107,7 +107,7 @@ public class AudioManagerTest extends InstrumentationTestCase {
private final static String TAG = "AudioManagerTest";
private final static long ASYNC_TIMING_TOLERANCE_MS = 50;
- private final static long POLL_TIME_VOLUME_ADJUST = 200;
+ private final static long POLL_TIME_VOLUME_ADJUST = 400;
private final static long POLL_TIME_UPDATE_INTERRUPTION_FILTER = 5000;
private final static int MP3_TO_PLAY = R.raw.testmp3; // ~ 5 second mp3
private final static long POLL_TIME_PLAY_MUSIC = 2000;
diff --git a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
index ac09cef061c..3de299c8265 100644
--- a/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
+++ b/tests/tests/media/player/src/android/media/player/cts/MediaPlayerTest.java
@@ -115,6 +115,8 @@ public class MediaPlayerTest extends MediaPlayerTestBase {
private static final int RECORDED_VIDEO_HEIGHT = 144;
private static final long RECORDED_DURATION_MS = 3000;
private static final float FLOAT_TOLERANCE = .0001f;
+ private static final int PLAYBACK_DURATION_MS = 10000;
+ private static final int ANR_DETECTION_TIME_MS = 20000;
private final Vector<Integer> mTimedTextTrackIndex = new Vector<>();
private final Monitor mOnTimedTextCalled = new Monitor();
@@ -713,9 +715,9 @@ public class MediaPlayerTest extends MediaPlayerTestBase {
player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
player.prepare();
// Test needs the mediaplayer to playback at least about 5 seconds of content.
- // Clip used here has a duration of 61 seconds, so seek to 50 seconds in the media file.
+ // Clip used here has a duration of 61 seconds, given PLAYBACK_DURATION_MS for play.
// This leaves enough remaining time, with gapless enabled or disabled,
- player.seekTo(50000);
+ player.seekTo(player.getDuration() - PLAYBACK_DURATION_MS);
}
}
@@ -757,6 +759,8 @@ public class MediaPlayerTest extends MediaPlayerTestBase {
@Test
public void testSetNextMediaPlayer() throws Exception {
+ final int TOTAL_TIMEOUT_MS = PLAYBACK_DURATION_MS * 4 + ANR_DETECTION_TIME_MS
+ + 5000 /* listener latency(ms) */;
initMediaPlayer(mMediaPlayer);
final Monitor mTestCompleted = new Monitor();
@@ -770,9 +774,9 @@ public class MediaPlayerTest extends MediaPlayerTestBase {
return;
}
long now = SystemClock.elapsedRealtime();
- if ((now - startTime) > 45000) {
- // We've been running for 45 seconds and still aren't done, so we're stuck
- // somewhere. Signal ourselves to dump the thread stacks.
+ if ((now - startTime) > TOTAL_TIMEOUT_MS) {
+ // We've been running beyond TOTAL_TIMEOUT and still aren't done,
+ // so we're stuck somewhere. Signal ourselves to dump the thread stacks.
android.os.Process.sendSignal(android.os.Process.myPid(), 3);
SystemClock.sleep(2000);
fail("Test is stuck, see ANR stack trace for more info. You may need to" +
diff --git a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/BaseTestCase.java b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/BaseTestCase.java
index f5b0140667c..b0cbdcbc9fe 100644
--- a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/BaseTestCase.java
+++ b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/BaseTestCase.java
@@ -17,6 +17,7 @@
package android.security.net.config.cts;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.test.AndroidTestCase;
@@ -26,16 +27,28 @@ import com.android.compatibility.common.util.SystemUtil;
* Base test case for all tests under {@link android.security.net.config.cts}.
*/
public class BaseTestCase extends AndroidTestCase {
+
+ private boolean isWifiSupported(Context context) {
+ final PackageManager packageManager = context.getPackageManager();
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+ }
+
@Override
public void setUp() throws Exception {
// Instant Apps cannot access WifiManager, skip wifi check.
if (getContext().getPackageManager().isInstantApp()) {
return;
}
+
+ // Skip accessing wifi manager if Wifi feature is not supported.
+ if (!isWifiSupported(getContext())) {
+ return;
+ }
+
WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()) {
SystemUtil.runShellCommand("svc wifi enable"); // toggle wifi on.
- Thread.sleep(5000); // sleep 5 second for wifi to connect to a network.
+ Thread.sleep(6000); // sleep 6 second for wifi to connect to a network.
}
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
index fd7e977b118..030f341aa74 100644
--- a/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NoWakeLockPermissionTest.java
@@ -17,6 +17,8 @@
package android.permission.cts;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
import android.content.Context;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
@@ -49,6 +51,10 @@ public class NoWakeLockPermissionTest extends AndroidTestCase {
@AppModeFull(reason = "Instant apps cannot access the WifiManager")
@SmallTest
public void testWifiLockAcquire() {
+ if (!mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI)) {
+ return;
+ }
+
final WifiManager wifiManager = (WifiManager) mContext.getSystemService(
Context.WIFI_SERVICE);
final WifiLock wifiLock = wifiManager.createWifiLock("WakeLockPermissionTest");
diff --git a/tests/tests/permission/src/android/permission/cts/NoWifiStatePermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoWifiStatePermissionTest.java
index d8acd507d26..6be8d7d4690 100644
--- a/tests/tests/permission/src/android/permission/cts/NoWifiStatePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NoWifiStatePermissionTest.java
@@ -16,6 +16,8 @@
package android.permission.cts;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -32,10 +34,17 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
private static final int TEST_NET_ID = 1;
private static final WifiConfiguration TEST_WIFI_CONFIGURATION = new WifiConfiguration();
private WifiManager mWifiManager;
+ private boolean mHasWifi;
@Override
protected void setUp() throws Exception {
super.setUp();
+
+ mHasWifi = mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI);
+ if (!mHasWifi) {
+ return;
+ }
+
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
assertNotNull(mWifiManager);
}
@@ -46,6 +55,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
*/
public void testGetWifiState() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.getWifiState();
fail("WifiManager.getWifiState didn't throw SecurityException as expected");
@@ -60,6 +73,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
*/
public void testGetConfiguredNetworks() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.getConfiguredNetworks();
fail("WifiManager.getConfiguredNetworks didn't throw SecurityException as expected");
@@ -74,6 +91,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
*/
public void testGetConnectionInfo() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.getConnectionInfo();
fail("WifiManager.getConnectionInfo didn't throw SecurityException as expected");
@@ -88,6 +109,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
*/
public void testGetScanResults() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.getScanResults();
fail("WifiManager.getScanResults didn't throw SecurityException as expected");
@@ -102,6 +127,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
*/
public void testGetDhcpInfo() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.getDhcpInfo();
fail("WifiManager.getDhcpInfo didn't throw SecurityException as expected");
@@ -116,6 +145,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testDisconnect() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.disconnect();
fail("WifiManager.disconnect didn't throw SecurityException as expected");
@@ -130,6 +163,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testReconnect() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.reconnect();
fail("WifiManager.reconnect didn't throw SecurityException as expected");
@@ -144,6 +181,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testReassociate() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.reassociate();
fail("WifiManager.reassociate didn't throw SecurityException as expected");
@@ -158,6 +199,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testAddNetwork() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.addNetwork(TEST_WIFI_CONFIGURATION);
fail("WifiManager.addNetwork didn't throw SecurityException as expected");
@@ -172,6 +217,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testUpdateNetwork() {
+ if (!mHasWifi) {
+ return;
+ }
+
TEST_WIFI_CONFIGURATION.networkId = 2;
try {
@@ -188,6 +237,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testRemoveNetwork() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.removeNetwork(TEST_NET_ID);
fail("WifiManager.removeNetwork didn't throw SecurityException as expected");
@@ -202,6 +255,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testEnableNetwork() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.enableNetwork(TEST_NET_ID, false);
fail("WifiManager.enableNetwork didn't throw SecurityException as expected");
@@ -216,6 +273,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testDisableNetwork() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.disableNetwork(TEST_NET_ID);
fail("WifiManager.disableNetwork didn't throw SecurityException as expected");
@@ -230,6 +291,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testPingSupplicant() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.pingSupplicant();
fail("WifiManager.pingSupplicant didn't throw SecurityException as expected");
@@ -244,6 +309,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testStartScan() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.startScan();
fail("WifiManager.startScan didn't throw SecurityException as expected");
@@ -258,6 +327,10 @@ public class NoWifiStatePermissionTest extends AndroidTestCase {
* {@link android.Manifest.permission#CHANGE_WIFI_STATE}.
*/
public void testSetWifiEnabled() {
+ if (!mHasWifi) {
+ return;
+ }
+
try {
mWifiManager.setWifiEnabled(true);
fail("WifiManager.setWifiEnabled didn't throw SecurityException as expected");
diff --git a/tests/tests/permission2/res/raw/wear_android_manifest.xml b/tests/tests/permission2/res/raw/wear_android_manifest.xml
deleted file mode 100644
index 08488bc3d72..00000000000
--- a/tests/tests/permission2/res/raw/wear_android_manifest.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<!-- This file contains permissions which were back ported.
- These permissions are already present on future platform releases.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android" coreApp="true" android:sharedUserId="android.uid.system"
- android:sharedUserLabel="@string/android_system_label">
-
- <!-- @hide Allows an application to access wrist temperature data from the watch sensors.
- <p class="note"><strong>Note: </strong> This permission is for Wear OS only.
- <p>Protection level: dangerous -->
- <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE"
- android:permissionGroup="android.permission-group.UNDEFINED"
- android:label="@string/permlab_bodySensorsWristTemperature"
- android:description="@string/permdesc_bodySensorsWristTemperature"
- android:backgroundPermission="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"
- android:protectionLevel="dangerous" />
-
- <!-- @hide Allows an application to access wrist temperature data from the watch sensors.
- If you're requesting this permission, you must also request
- {@link #BODY_SENSORS_WRIST_TEMPERATURE}. Requesting this permission by itself doesn't
- give you wrist temperature body sensors access.
- <p class="note"><strong>Note: </strong> This permission is for Wear OS only.
- <p>Protection level: dangerous
-
- <p> This is a hard restricted permission which cannot be held by an app until
- the installer on record allowlists the permission. For more details see
- {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
- -->
- <permission android:name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"
- android:permissionGroup="android.permission-group.UNDEFINED"
- android:label="@string/permlab_bodySensors_wristTemperature_background"
- android:description="@string/permdesc_bodySensors_wristTemperature_background"
- android:protectionLevel="dangerous"
- android:permissionFlags="hardRestricted" />
-
-</manifest> \ No newline at end of file
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 637380313a2..576df286de4 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -176,9 +176,6 @@ public class PermissionPolicyTest {
}
declaredPermissionsMap.putAll(carServiceBuiltInPermissionsMap);
}
- if (sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- expectedPermissions.addAll(loadExpectedPermissions(R.raw.wear_android_manifest));
- }
for (ExpectedPermissionInfo expectedPermission : expectedPermissions) {
String expectedPermissionName = expectedPermission.name;
diff --git a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
index 2a9f815aec5..e10131c3f66 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
+++ b/tests/tests/permission2/src/android/permission2/cts/RuntimePermissionProperties.kt
@@ -55,7 +55,6 @@ import android.Manifest.permission.WRITE_CONTACTS
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.Manifest.permission_group.UNDEFINED
import android.app.AppOpsManager.permissionToOp
-import android.content.pm.PackageManager
import android.content.pm.PackageManager.GET_PERMISSIONS
import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS
import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP
@@ -166,24 +165,6 @@ class RuntimePermissionProperties {
// Add runtime permissions added in U which were _not_ split from a previously existing
// runtime permission
expectedPerms.add(READ_MEDIA_VISUAL_USER_SELECTED)
-
- // Add runtime permissions added in V (back ported from U) which were _not_ split from a
- // previously existing runtime permission
- if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- expectedPerms.add(BODY_SENSORS_WRIST_TEMPERATURE)
- expectedPerms.add(BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND)
- }
-
assertThat(expectedPerms).containsExactlyElementsIn(platformRuntimePerms.map { it.name })
}
-
- companion object {
- // These permissions are back ported from Android U to tm-wear, hidden in the
- // "core/res/AndroidManifest.xml" file of /framework/base repo. Added these 2 constants here
- // because hidden permissions can't be imported like other imported permissions in this file
- private const val BODY_SENSORS_WRIST_TEMPERATURE =
- "android.permission.BODY_SENSORS_WRIST_TEMPERATURE"
- private const val BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND =
- "android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"
- }
}
diff --git a/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt b/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
index 104655f3bde..3c8a35c058d 100644
--- a/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
+++ b/tests/tests/permission3/CreateNotificationChannelsApp31/src/android/permission3/cts/usepermission/CreateNotificationChannelsActivity.kt
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Intent
import android.content.pm.PackageManager
+import android.os.Bundle
import android.os.Handler
import android.os.Looper
@@ -43,9 +44,13 @@ class CreateNotificationChannelsActivity : Activity() {
lateinit var notificationManager: NotificationManager
var launchActivityOnSecondResume = false
var isFirstResume = true
+ var windowHasFocus = false
+ var pendingCreateChannel = false
val handler = Handler(Looper.getMainLooper())
- override fun onStart() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
val launchSecondActivity = intent.getBooleanExtra(EXTRA_START_SECOND_ACTIVITY, false)
notificationManager = baseContext.getSystemService(NotificationManager::class.java)!!
if (intent.getBooleanExtra(EXTRA_START_SECOND_APP, false)) {
@@ -73,7 +78,6 @@ class CreateNotificationChannelsActivity : Activity() {
}
}
-
if (intent.getBooleanExtra(EXTRA_REQUEST_OTHER_PERMISSIONS, false)) {
requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 0)
} else if (intent.getBooleanExtra(EXTRA_REQUEST_OTHER_PERMISSIONS_DELAYED, false)) {
@@ -85,8 +89,6 @@ class CreateNotificationChannelsActivity : Activity() {
if (intent.getBooleanExtra(EXTRA_REQUEST_NOTIF_PERMISSION, false)) {
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
}
-
- super.onStart()
}
private fun launchSecondActivity() {
@@ -99,7 +101,21 @@ class CreateNotificationChannelsActivity : Activity() {
}, LONG_DELAY_MS)
}
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ windowHasFocus = hasFocus
+ if (windowHasFocus && pendingCreateChannel) {
+ pendingCreateChannel = false
+ createChannel()
+ }
+ }
+
private fun createChannel() {
+ // Wait until window has focus so the permission prompt can be displayed
+ if (!windowHasFocus) {
+ pendingCreateChannel = true
+ return
+ }
+
if (notificationManager.getNotificationChannel(CHANNEL_ID_31) == null) {
notificationManager.createNotificationChannel(NotificationChannel(CHANNEL_ID_31,
"Foreground Services", NotificationManager.IMPORTANCE_HIGH))
diff --git a/tests/tests/permission3/CreateNotificationChannelsApp33/Android.bp b/tests/tests/permission3/CreateNotificationChannelsApp33/Android.bp
index 876b68f350a..293897c2c52 100644
--- a/tests/tests/permission3/CreateNotificationChannelsApp33/Android.bp
+++ b/tests/tests/permission3/CreateNotificationChannelsApp33/Android.bp
@@ -23,7 +23,7 @@ android_test_helper_app {
defaults: ["mts-target-sdk-version-current"],
// TODO ntmyren: change to "33" when it is a valid target
sdk_version: "test_current",
- min_sdk_version: "test_current",
+ min_sdk_version: "current",
static_libs: [
"kotlin-stdlib",
diff --git a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
index d55e3a400b1..dee76c2fc9d 100644
--- a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
@@ -194,6 +194,7 @@ class NotificationPermissionTest : BaseUsePermissionTest() {
fun notificationPromptShownForSubsequentStartsIfTaskStartWasLauncher() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
launchApp(startSecondActivity = true)
+ waitFindObject(By.res(ALLOW_BUTTON))
pressBack()
clickPermissionRequestAllowButton()
}
diff --git a/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
index 0b88e01f772..7499e0f2c04 100644
--- a/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/SensorBlockedBannerTest.kt
@@ -65,6 +65,7 @@ class SensorBlockedBannerTest : BaseUsePermissionTest() {
@Before
fun setup() {
Assume.assumeFalse(isTv)
+ Assume.assumeFalse(isWatch)
// TODO(b/203784852) Auto will eventually support the blocked sensor banner, but there won't
// be support in T or below
Assume.assumeFalse(isAutomotive)
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index 5ad3cf53e0c..48f55befa1f 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -279,7 +279,8 @@ public class ProviderTestUtils {
// file creation fails, we ignore and let `dd` command create it instead.
}
- executeShellCommand(String.format("dd bs=1 if=%s skip=%d count=%d of=%s",
+ executeShellCommand(String.format(
+ "dd bs=4K if=%s iflag=skip_bytes,count_bytes skip=%d count=%d of=%s",
source.getAbsolutePath(), skip, count, file.getAbsolutePath()));
// Force sync to try updating other views
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java
new file mode 100644
index 00000000000..4834cb3d621
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkMimeTypeMapTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.MimeTypeMapTest");
+
+ @Test
+ public void testGetFileExtensionFromUrl() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetFileExtensionFromUrl");
+ }
+
+ @Test
+ public void testHasMimeType() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testHasMimeType");
+ }
+
+ @Test
+ public void testGetMimeTypeFromExtension() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetMimeTypeFromExtension");
+ }
+
+ @Test
+ public void testHasExtension() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testHasExtension");
+ }
+
+ @Test
+ public void testGetExtensionFromMimeType() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetExtensionFromMimeType");
+ }
+
+ @Test
+ public void testGetSingleton() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetSingleton");
+ }
+}
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java
new file mode 100644
index 00000000000..e83a333463e
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkServiceWorkerWebSettingsTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.ServiceWorkerWebSettingsTest");
+
+ @Test
+ public void testCacheMode() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testCacheMode");
+ }
+
+ @Test
+ public void testAllowContentAccess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testAllowContentAccess");
+ }
+
+ @Test
+ public void testAllowFileAccess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testAllowFileAccess");
+ }
+
+ @Test
+ public void testBlockNetworkLoads() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testBlockNetworkLoads");
+ }
+}
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java
new file mode 100644
index 00000000000..91f3fbedaec
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkWebViewRenderProcessTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.WebViewRenderProcessTest");
+
+ @Test
+ public void testGetWebViewRenderProcess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetWebViewRenderProcess");
+ }
+}
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 56d02d21ee3..989edcac454 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -104,6 +104,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert1",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-1",
manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
}
@@ -111,6 +113,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert1Dup",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-1",
manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
}
@@ -118,6 +122,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert2",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-2",
manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
}
@@ -125,6 +131,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert3",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-3",
manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
}
@@ -132,6 +140,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert4",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-4",
manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
}
@@ -139,6 +149,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert12",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-1",
additional_certificates: [
":permission-test-cert-2",
@@ -149,6 +161,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert12Dup",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-1",
additional_certificates: [
":permission-test-cert-2",
@@ -159,6 +173,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert34",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-3",
additional_certificates: [
":permission-test-cert-4",
@@ -169,6 +185,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert123",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-1",
additional_certificates: [
":permission-test-cert-2",
@@ -180,6 +198,8 @@ android_test_helper_app {
android_test_helper_app {
name: "CtsPermissionBackupAppCert4History124",
min_sdk_version: "30",
+ resource_dirs: [],
+ asset_dirs: [],
certificate: ":permission-test-cert-4",
additional_certificates: [
":permission-test-cert-1",
@@ -197,6 +217,8 @@ android_app_certificate {
android_test_helper_app {
name: "RolePermissionOverrideTestApp",
+ resource_dirs: [],
+ asset_dirs: [],
manifest: "testdata/rolepermissionoverridetestapp.xml",
}
diff --git a/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
index 9c1a33985f3..4ed5e452d2b 100644
--- a/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
+++ b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
@@ -20,4 +20,5 @@ interface IIsolatedService {
String[] getCachedSystemServices();
IBinder getSystemService(String serviceName);
boolean getProcessIsIsolated();
+ void registerBroadcastReceiver();
}
diff --git a/tests/tests/security/res/values/strings.xml b/tests/tests/security/res/values/strings.xml
index 73dd5b93d2c..ee1f73ee241 100644
--- a/tests/tests/security/res/values/strings.xml
+++ b/tests/tests/security/res/values/strings.xml
@@ -25,4 +25,11 @@
VoicemailSettingsActivity</string>
<string name="cve_2021_0642_msgResolveErrorPocAction">The intent with action
CVE_2021_0642_ACTION should not be resolved to test package</string>
+
+ <!-- CVE-2023-20338 -->
+ <string name="cve_2022_20338_authority">google.com</string>
+ <string name="cve_2022_20338_failMsg">Device is vulnerable to b/171966843 !!</string>
+ <string name="cve_2022_20338_invalidURL">https://google.com@evil.com</string>
+ <string name="cve_2022_20338_path">@evil.com</string>
+ <string name="cve_2022_20338_scheme">https</string>
</resources>
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20338.java b/tests/tests/security/src/android/security/cts/CVE_2022_20338.java
new file mode 100644
index 00000000000..15de30af076
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20338.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcel;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20338 extends StsExtraBusinessLogicTestCase {
+
+ // b/171966843
+ // Vulnerable package : framework.jar
+ // Vulnerable app : Not applicable
+ @AsbSecurityTest(cveBugId = 171966843)
+ @Test
+ public void testPocCVE_2022_20338() {
+ try {
+ Context context = getInstrumentation().getContext();
+
+ final int representation = 1 /* REPRESENTATION_ENCODED */;
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInt(3 /* HierarchicalUri.TYPE_ID */);
+ parcel.writeByteArray((context.getString(R.string.cve_2022_20338_scheme)).getBytes());
+ parcel.writeInt(representation);
+ parcel.writeByteArray(
+ (context.getString(R.string.cve_2022_20338_authority)).getBytes());
+ parcel.writeInt(representation);
+ parcel.writeByteArray((context.getString(R.string.cve_2022_20338_path)).getBytes());
+ parcel.writeInt(representation);
+ parcel.writeByteArray(null /* query */);
+ parcel.writeInt(representation);
+ parcel.writeByteArray(null /* fragment */);
+ parcel.setDataPosition(0);
+ Uri uri = Uri.CREATOR.createFromParcel(parcel);
+
+ // on vulnerable device, the uri format will be incorrect due to improper input
+ // validation. The test fails if the uri string matches the invalidURL.
+ assertFalse(
+ context.getString(R.string.cve_2022_20338_failMsg),
+ uri.toString().equals((context.getString(R.string.cve_2022_20338_invalidURL))));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2023_21087.java b/tests/tests/security/src/android/security/cts/CVE_2023_21087.java
new file mode 100644
index 00000000000..ddb55034830
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2023_21087.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2023_21087 extends StsExtraBusinessLogicTestCase {
+
+ @AsbSecurityTest(cveBugId = 261723753)
+ @Test
+ public void testPocCVE_2023_21087() {
+ try {
+ // Taking reference from the constant of the same name located at
+ // path:services\core\java\com\android\server\notification\PreferencesHelper.java
+ // and using twice it's original value as notificationChannelGroupCountLimit.
+ final int notificationChannelGroupCountLimit = 12000;
+
+ // Adding notification channel groups more than the set limit.
+ NotificationManager notificationManager =
+ getApplicationContext().getSystemService(NotificationManager.class);
+ try {
+ for (int i = 0; i < notificationChannelGroupCountLimit; ++i) {
+ NotificationChannelGroup group =
+ new NotificationChannelGroup(String.valueOf(i), String.valueOf(i));
+ notificationManager.createNotificationChannelGroup(group);
+ }
+ fail(
+ "Device is vulnerable to b/261723753 !! Allowed to create notification"
+ + " channel groups more than the current count limit of 6000");
+ } catch (IllegalStateException e) {
+
+ // In the presence of fix adding notification channel group above the limit
+ // will cause an IllegalStateException to occur so ignore.
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
index 91e39e8a5fe..6bf5733b6db 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
@@ -15,6 +15,8 @@
*/
package android.security.cts;
+import static org.junit.Assert.assertThrows;
+
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
@@ -27,17 +29,23 @@ import android.platform.test.annotations.AsbSecurityTest;
import android.security.cts.IIsolatedService;
import android.security.cts.IsolatedService;
import android.util.Log;
+
import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.ArrayUtils;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+
import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.After;
-import androidx.test.runner.AndroidJUnit4;
-import org.junit.runner.RunWith;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
@RunWith(AndroidJUnit4.class)
public class IsolatedProcessTest {
@@ -112,6 +120,11 @@ public class IsolatedProcessTest {
Assert.assertTrue(mService.getProcessIsIsolated());
}
+ @Test
+ public void testRegisterBroadcastListener() throws RemoteException {
+ assertThrows(SecurityException.class, () -> mService.registerBroadcastReceiver());
+ }
+
@After
public void tearDown() {
getInstrumentation().getContext().unbindService(mServiceConnection);
diff --git a/tests/tests/security/src/android/security/cts/IsolatedService.java b/tests/tests/security/src/android/security/cts/IsolatedService.java
index 094f689a669..d77ef65ef31 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedService.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedService.java
@@ -18,9 +18,13 @@ package android.security.cts;
import android.app.Service;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
+
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -79,6 +83,11 @@ public class IsolatedService extends Service {
return Process.isIsolated();
}
+ public void registerBroadcastReceiver() throws SecurityException {
+ BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(
+ getApplicationContext());
+ registerReceiver(receiver, new IntentFilter("testAction"));
+ }
};
@Override
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
index 15933b6e967..3bcb78ef8c1 100644
--- a/tests/tests/systemui/AndroidManifest.xml
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -29,13 +29,11 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application android:requestLegacyExternalStorage="true">
- <!-- Have LightBarActivity always take up the full screen, regardless of orientation,
- so it's never letterboxed. If the activity is letterboxed, then the status icons will
- be outside of the activity and the tests will fail. See b/246515090. -->
+ <!-- Have LightBarActivity always be in portrait orientation, since the test's screenshots
+ rely on portrait orientation. See b/260069585. -->
<activity android:name=".LightBarActivity"
android:theme="@android:style/Theme.Material.NoActionBar"
- android:screenOrientation="unspecified"
- android:resizeableActivity="true"/>
+ android:screenOrientation="portrait"/>
<activity android:name=".LightBarThemeActivity"
android:theme="@style/LightBarTheme"
android:screenOrientation="portrait"/>
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index 50792176d28..c09cb536d3c 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -41,6 +41,7 @@ import android.os.SystemClock;
import android.permission.PermissionManager;
import android.permission.cts.PermissionUtils;
import android.platform.test.annotations.AppModeFull;
+import android.server.wm.IgnoreOrientationRequestSession;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -54,6 +55,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.ThrowingRunnable;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
@@ -86,6 +89,7 @@ public class LightBarTests extends LightBarTestBase {
private final String NOTIFICATION_CHANNEL_ID = "test_channel";
private final String NOTIFICATION_GROUP_KEY = "test_group";
private NotificationManager mNm;
+ private IgnoreOrientationRequestSession mOrientationRequestSession;
@Rule
public ActivityTestRule<LightBarActivity> mActivityRule = new ActivityTestRule<>(
@@ -93,6 +97,28 @@ public class LightBarTests extends LightBarTestBase {
@Rule
public TestName mTestName = new TestName();
+
+
+ @Before
+ public void setUp() {
+ // We need to prevent letterboxing because when an activity is letterboxed, then the status
+ // bar icons are outside the activity space so our verification will fail. See b/246515090.
+ //
+ // When ignore_orientation_request is set to true and the device is in landscape but the
+ // activity is in portrait, then the device remains in landscape but letterboxes the
+ // activity (so the activity is *not* full screen). Setting ignore_orientation_request to
+ // false will cause the device to instead rotate to portrait to match the activity, thus
+ // preventing letterboxing.
+ mOrientationRequestSession = new IgnoreOrientationRequestSession(false /* enable */);
+ }
+
+ @After
+ public void tearDown() {
+ if (mOrientationRequestSession != null) {
+ mOrientationRequestSession.close();
+ }
+ }
+
@Test
@AppModeFull // Instant apps cannot create notifications
public void testLightStatusBarIcons() throws Throwable {
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 57d09e7bec8..da8f52c7b87 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -96,6 +96,13 @@
</intent-filter>
</service>
+ <service android:name=".NullBindingCallRedirectionServiceController"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telecom.cts.ACTION_CONTROL_CALL_REDIRECTION_SERVICE"/>
+ </intent-filter>
+ </service>
+
<service android:name="android.telecom.cts.MockInCallService"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="true">
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index 53a36c93013..060afe9e305 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -25,7 +25,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -33,13 +32,14 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
-
import android.telecom.Call;
import android.telecom.PhoneAccount;
+import android.telecom.TelecomManager;
import android.telecom.cts.redirectiontestapp.CtsCallRedirectionService;
import android.telecom.cts.redirectiontestapp.CtsCallRedirectionServiceController;
import android.telecom.cts.redirectiontestapp.ICtsCallRedirectionServiceController;
import android.text.TextUtils;
+import android.util.Log;
import com.android.compatibility.common.util.CddTest;
@@ -91,7 +91,7 @@ public class CallRedirectionServiceTest extends BaseTelecomTestWithMockServices
NewOutgoingCallBroadcastReceiver.reset();
mHandler = new Handler(Looper.getMainLooper());
mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
- setupControlBinder();
+ setupControlBinder(null, null);
setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
rememberPreviousCallRedirectionApp();
// Ensure CTS app holds the call redirection role.
@@ -230,16 +230,46 @@ public class CallRedirectionServiceTest extends BaseTelecomTestWithMockServices
assertFalse(mCallRedirectionServiceController.waitForOnPlaceCallInvoked());
}
+ public void testServiceUnbindOnNullBinding()
+ throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+ // Set up control binder using NullBindingCallRedirectionServiceController.
+ // This will invoke onNullBinding.
+ setupControlBinder(NullBindingCallRedirectionServiceController.CONTROL_INTERFACE_ACTION,
+ NullBindingCallRedirectionServiceController.CONTROL_INTERFACE_COMPONENT);
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
+ mTelecomManager.placeCall(createTestNumber(), extras);
+ TestUtils.waitOnLocalMainLooper(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ // Assert bind and unbind latch countdown
+ assertTrue(TestUtils.waitForLatchCountDown(
+ NullBindingCallRedirectionServiceController.sBindLatch));
+ assertTrue(TestUtils.waitForLatchCountDown(
+ NullBindingCallRedirectionServiceController.sUnbindLatch));
+ }
+
/**
* Sets up a binder used to control the CallRedirectionServiceCtsTestApp.
* This app is a standalone APK so that it can reside in a package name outside of the one the
* CTS test itself runs in.
* @throws InterruptedException
*/
- private void setupControlBinder() throws InterruptedException {
- Intent bindIntent = new Intent(
- CtsCallRedirectionServiceController.CONTROL_INTERFACE_ACTION);
- bindIntent.setComponent(CtsCallRedirectionServiceController.CONTROL_INTERFACE_COMPONENT);
+ private void setupControlBinder(String interfaceAction,
+ ComponentName interfaceComponentName) throws InterruptedException {
+ if (interfaceAction == null) {
+ interfaceAction = CtsCallRedirectionServiceController.CONTROL_INTERFACE_ACTION;
+ }
+ if (interfaceComponentName == null) {
+ interfaceComponentName =
+ CtsCallRedirectionServiceController.CONTROL_INTERFACE_COMPONENT;
+ }
+
+ Intent bindIntent = new Intent(interfaceAction);
+ bindIntent.setComponent(interfaceComponentName);
final CountDownLatch bindLatch = new CountDownLatch(1);
boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
@@ -253,6 +283,15 @@ public class CallRedirectionServiceTest extends BaseTelecomTestWithMockServices
public void onServiceDisconnected(ComponentName name) {
mCallRedirectionServiceController = null;
}
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ // This path will only be hit if NullBindingCallRedirectionServiceController is set
+ // as the controller.
+ Log.i(TAG, "onNullBinding: null binding received from onBind");
+ bindLatch.countDown();
+ mContext.unbindService(this);
+ }
}, Context.BIND_AUTO_CREATE);
if (!success) {
fail("Failed to get control interface -- bind error");
diff --git a/tests/tests/telecom/src/android/telecom/cts/NullBindingCallRedirectionServiceController.java b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallRedirectionServiceController.java
new file mode 100644
index 00000000000..2ffc6d65ee9
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/NullBindingCallRedirectionServiceController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+public class NullBindingCallRedirectionServiceController extends Service {
+ private static final String TAG = NullBindingCallRedirectionServiceController.class
+ .getSimpleName();
+ public static final String CONTROL_INTERFACE_ACTION =
+ "android.telecom.cts.ACTION_CONTROL_CALL_REDIRECTION_SERVICE";
+ public static final ComponentName CONTROL_INTERFACE_COMPONENT =
+ ComponentName.unflattenFromString(
+ "android.telecom.cts/.NullBindingCallRedirectionServiceController");
+
+ public static CountDownLatch sBindLatch = new CountDownLatch(1);
+ public static CountDownLatch sUnbindLatch = new CountDownLatch(1);
+
+ private static NullBindingCallRedirectionServiceController
+ sCallRedirectionServiceController = null;
+
+
+ public static NullBindingCallRedirectionServiceController getInstance() {
+ return sCallRedirectionServiceController;
+ }
+
+ public static void resetBindLatches() {
+ sBindLatch = new CountDownLatch(1);
+ sUnbindLatch = new CountDownLatch(1);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i(TAG, "onBind: returning null binding");
+ sCallRedirectionServiceController = this;
+ // Treat case as null binding from onBind. This should hit onNullBinding.
+ sUnbindLatch = new CountDownLatch(1);
+ sBindLatch.countDown();
+ return null;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i(TAG, "onUnbind: unbinding service");
+ sCallRedirectionServiceController = null;
+ sUnbindLatch.countDown();
+ return false;
+ }
+}
+
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 cf46203dbcb..291ce7c2bab 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -1210,10 +1210,8 @@ public class TelephonyManagerTest {
Build::getSerial);
assertNotNull("Non-telephony devices must have a Build.getSerial() number.",
serial);
- assertTrue("Hardware id must be no longer than 20 characters.",
- serial.length() <= 20);
assertTrue("Hardware id must be alphanumeric.",
- Pattern.matches("[0-9A-Za-z]+", serial));
+ Pattern.matches("[0-9A-Za-z.,_-]+", serial));
}
private void assertMacAddress(String macAddress) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
index 7a91ab9ed79..08666e20809 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
@@ -81,7 +81,9 @@ class DrawActivity : Activity() {
}
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
- View.SYSTEM_UI_FLAG_FULLSCREEN
+ View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
window.decorView.keepScreenOn = true
mHandler = RenderSpecHandler()
diff --git a/tests/tests/view/src/android/view/cts/OWNERS b/tests/tests/view/src/android/view/cts/OWNERS
index b7cb83689dc..3ecbdbc6e14 100644
--- a/tests/tests/view/src/android/view/cts/OWNERS
+++ b/tests/tests/view/src/android/view/cts/OWNERS
@@ -2,6 +2,7 @@ per-file ASurfaceControlBackPressureTest.java = file:platform/frameworks/base:/s
per-file ASurfaceControlTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
per-file AttachedSurfaceControlSyncTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
per-file AttachedSurfaceControlTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
+per-file SetTouchableRegionTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
per-file SurfaceViewSyncTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
per-file *ScrollCapture*.java = file:platform/frameworks/base:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
index c89cdb858d6..9cff62b816c 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
@@ -72,6 +72,9 @@ public class PixelCopyViewProducerActivity extends Activity implements OnDrawLis
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
mContent.getViewTreeObserver().addOnDrawListener(this);
mContent.setOnApplyWindowInsetsListener(this);
+
+ //setDecorFitsSystemWindows to false will ignore the cutout
+ getWindow().setDecorFitsSystemWindows(false);
}
@Override
diff --git a/tests/tests/view/src/android/view/cts/SetTouchableRegionTest.java b/tests/tests/view/src/android/view/cts/SetTouchableRegionTest.java
index ad73c21fb3a..2cf7b5c41f2 100644
--- a/tests/tests/view/src/android/view/cts/SetTouchableRegionTest.java
+++ b/tests/tests/view/src/android/view/cts/SetTouchableRegionTest.java
@@ -16,14 +16,17 @@
package android.view.cts;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Instrumentation;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Region;
-import android.view.AttachedSurfaceControl;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -33,22 +36,18 @@ import android.widget.PopupWindow;
import com.android.compatibility.common.util.CtsTouchUtils;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
+import androidx.test.core.app.ActivityScenario;
import androidx.test.runner.AndroidJUnit4;
@RunWith(AndroidJUnit4.class)
public class SetTouchableRegionTest {
private Instrumentation mInstrumentation;
private Activity mActivity;
- @Rule
- public ActivityTestRule<CtsActivity> mActivityRule =
- new ActivityTestRule<>(CtsActivity.class);
+ private ActivityScenario<CtsActivity> mScenario;
class MotionRecordingView extends View {
public MotionRecordingView(Context context) {
@@ -80,20 +79,28 @@ public class SetTouchableRegionTest {
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mActivity = mActivityRule.getActivity();
+ // Launch activity in fullscreen windowing mode
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(mInstrumentation.getTargetContext(), CtsActivity.class);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mScenario = ActivityScenario.launch(intent, options.toBundle());
+ mScenario.onActivity(activity -> {
+ mActivity = activity;
+ });
}
void tapSync() {
mInstrumentation.waitForIdleSync();
assertFalse(mMotionRecordingView.gotEvent());
- CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mMotionRecordingView);
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, null, mMotionRecordingView);
mInstrumentation.waitForIdleSync();
}
@Test
public void testClickthroughRegion() throws Throwable {
- mActivityRule.runOnUiThread(() -> {
+ mScenario.onActivity(activity -> {
mMotionRecordingView = new MotionRecordingView(mActivity);
mActivity.setContentView(mMotionRecordingView);
});
@@ -101,7 +108,7 @@ public class SetTouchableRegionTest {
// We have a view filling our entire hierarchy and so a tap should reach it
assertTrue(mMotionRecordingView.gotEvent());
- mActivityRule.runOnUiThread(() -> {
+ mScenario.onActivity(activity -> {
mPopupView = new View(mActivity);
PopupWindow popup = new PopupWindow(mPopupView,
ViewGroup.LayoutParams.FILL_PARENT,
@@ -114,7 +121,7 @@ public class SetTouchableRegionTest {
// and so the tap should not reach us
assertFalse(mMotionRecordingView.gotEvent());
- mActivityRule.runOnUiThread(() -> {
+ mScenario.onActivity(activity -> {
mPopupView.getRootSurfaceControl().setTouchableRegion(new Region());
});
tapSync();
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
index c4f36b7c8e4..08c2231673a 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/ASurfaceControlTestActivity.java
@@ -97,6 +97,7 @@ public class ASurfaceControlTestActivity extends Activity {
decorView.setPointerIcon(
PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL));
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ getWindow().setDecorFitsSystemWindows(false);
mLayoutParams = new FrameLayout.LayoutParams(DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT,
Gravity.LEFT | Gravity.TOP);
@@ -156,6 +157,12 @@ public class ASurfaceControlTestActivity extends Activity {
}
public void verifyScreenshot(PixelChecker pixelChecker, TestName name) {
+ int retries = 0;
+ int maxRetries = 2;
+ int numMatchingPixels = 0;
+ Rect bounds = null;
+ boolean success = false;
+
// Wait for the stable insets update. The position of the surface view is in correct before
// the update. Sometimes this callback isn't called, so we don't want to fail the test
// because it times out.
@@ -163,33 +170,44 @@ public class ASurfaceControlTestActivity extends Activity {
Log.w(TAG, "Insets animation wait timed out.");
}
- final CountDownLatch countDownLatch = new CountDownLatch(1);
- UiAutomation uiAutomation = mInstrumentation.getUiAutomation();
- mHandler.post(() -> {
- mScreenshot = uiAutomation.takeScreenshot(getWindow());
- mParent.removeAllViews();
- countDownLatch.countDown();
- });
-
- try {
- countDownLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS);
- } catch (Exception e) {
- }
-
- assertNotNull(mScreenshot);
+ while (retries < maxRetries) {
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ UiAutomation uiAutomation = mInstrumentation.getUiAutomation();
+ mHandler.post(() -> {
+ mScreenshot = uiAutomation.takeScreenshot(getWindow());
+ countDownLatch.countDown();
+ });
- Bitmap swBitmap = mScreenshot.copy(Bitmap.Config.ARGB_8888, false);
- mScreenshot.recycle();
+ try {
+ countDownLatch.await(WAIT_TIMEOUT_S, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ }
- int numMatchingPixels = pixelChecker.getNumMatchingPixels(swBitmap);
- Rect bounds = pixelChecker.getBoundsToCheck(swBitmap);
- boolean success = pixelChecker.checkPixels(numMatchingPixels, swBitmap.getWidth(),
- swBitmap.getHeight());
- if (!success) {
- saveFailureCapture(swBitmap, name);
+ assertNotNull(mScreenshot);
+
+ Bitmap swBitmap = mScreenshot.copy(Bitmap.Config.ARGB_8888, false);
+ mScreenshot.recycle();
+
+ numMatchingPixels = pixelChecker.getNumMatchingPixels(swBitmap);
+ bounds = pixelChecker.getBoundsToCheck(swBitmap);
+ success = pixelChecker.checkPixels(numMatchingPixels, swBitmap.getWidth(),
+ swBitmap.getHeight());
+ if (!success) {
+ saveFailureCapture(swBitmap, name);
+ swBitmap.recycle();
+ retries++;
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ }
+ } else {
+ swBitmap.recycle();
+ break;
+ }
}
- swBitmap.recycle();
-
+ mHandler.post(() -> {
+ mParent.removeAllViews();
+ });
assertTrue("Actual matched pixels:" + numMatchingPixels
+ " Bitmap size:" + bounds.width() + "x" + bounds.height(), success);
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java b/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
index d112353ce19..b59d19c7878 100644
--- a/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
@@ -33,7 +33,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class MimeTypeMapTest {
+public class MimeTypeMapTest extends SharedWebViewTest{
private MimeTypeMap mMimeTypeMap;
@@ -42,6 +42,11 @@ public class MimeTypeMapTest {
mMimeTypeMap = MimeTypeMap.getSingleton();
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ return new SharedWebViewTestEnvironment.Builder().build();
+ }
+
@Test
public void testGetFileExtensionFromUrl() {
assertEquals("html", MimeTypeMap.getFileExtensionFromUrl("http://localhost/index.html"));
diff --git a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
index 8b0c7228cf2..33ee18733a0 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
@@ -38,8 +38,7 @@ import org.junit.runner.RunWith;
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class ServiceWorkerWebSettingsTest {
-
+public class ServiceWorkerWebSettingsTest extends SharedWebViewTest {
private ServiceWorkerWebSettings mSettings;
private WebViewOnUiThread mOnUiThread;
@@ -49,14 +48,10 @@ public class ServiceWorkerWebSettingsTest {
@Before
public void setUp() throws Exception {
- Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
- mActivityScenarioRule.getScenario().onActivity(activity -> {
- WebViewCtsActivity webViewCtsActivity = (WebViewCtsActivity) activity;
- WebView webview = webViewCtsActivity.getWebView();
- if (webview != null) {
- mOnUiThread = new WebViewOnUiThread(webview);
- }
- });
+ WebView webview = getTestEnvironment().getWebView();
+ if (webview != null) {
+ mOnUiThread = new WebViewOnUiThread(webview);
+ }
mSettings = ServiceWorkerController.getInstance().getServiceWorkerWebSettings();
}
@@ -67,6 +62,27 @@ public class ServiceWorkerWebSettingsTest {
}
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
+
+ SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder();
+
+ mActivityScenarioRule
+ .getScenario()
+ .onActivity(
+ activity -> {
+ WebView webView = ((WebViewCtsActivity) activity).getWebView();
+ builder.setHostAppInvoker(
+ SharedWebViewTestEnvironment.createHostAppInvoker(
+ activity))
+ .setContext(activity)
+ .setWebView(webView);
+ });
+
+ return builder.build();
+ }
+
/**
* This should remain functionally equivalent to
* androidx.webkit.ServiceWorkerWebSettingsCompatTest#testCacheMode. Modifications to this test
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
index 288932421ea..5f5e1183ed4 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
@@ -48,7 +48,7 @@ import java.util.concurrent.Future;
@AppModeFull
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class WebViewRenderProcessTest {
+public class WebViewRenderProcessTest extends SharedWebViewTest {
private WebViewOnUiThread mOnUiThread;
@Rule
@@ -57,14 +57,10 @@ public class WebViewRenderProcessTest {
@Before
public void setUp() throws Exception {
- Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
- mActivityScenarioRule.getScenario().onActivity(activity -> {
- WebViewCtsActivity webViewCtsActivity = (WebViewCtsActivity) activity;
- WebView webview = webViewCtsActivity.getWebView();
- if (webview != null) {
- mOnUiThread = new WebViewOnUiThread(webview);
- }
- });
+ WebView webview = getTestEnvironment().getWebView();
+ if (webview != null) {
+ mOnUiThread = new WebViewOnUiThread(webview);
+ }
}
@After
@@ -74,6 +70,26 @@ public class WebViewRenderProcessTest {
}
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
+
+ SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder();
+
+ mActivityScenarioRule
+ .getScenario()
+ .onActivity(
+ activity -> {
+ WebView webView = ((WebViewCtsActivity) activity).getWebView();
+ builder.setHostAppInvoker(
+ SharedWebViewTestEnvironment.createHostAppInvoker(
+ activity))
+ .setWebView(webView);
+ });
+
+ return builder.build();
+ }
+
private boolean terminateRenderProcessOnUiThread(
final WebViewRenderProcess renderer) {
return WebkitUtils.onMainThreadSync(() -> {
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index f75cabf52df..3d1a7a7d9ec 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -400,6 +400,8 @@
</style>
<style name="Theme.PopupWindowCtsActivity" parent="@android:style/Theme.Holo">
+ <item name="android:windowSwipeToDismiss">false</item>
+ <item name="android:windowLayoutInDisplayCutoutMode">never</item>
</style>
<style name="TextView_FontResource">
diff --git a/tests/tests/widget/res/values/themes.xml b/tests/tests/widget/res/values/themes.xml
index 938452e669c..374834a8d9d 100644
--- a/tests/tests/widget/res/values/themes.xml
+++ b/tests/tests/widget/res/values/themes.xml
@@ -25,7 +25,7 @@
<item name="themeString">@string/remoteviews_theme_string</item>
</style>
- <style name="HorizontalScrollViewCtsActivityTheme" parent="@android:style/Theme.DeviceDefault">
+ <style name="HorizontalScrollViewCtsActivityTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
<item name="android:windowSwipeToDismiss">false</item>
</style>
</resources>
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index c74f21b9eb7..d94667cb58b 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -16,6 +16,8 @@
package android.widget.cts;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -34,8 +36,10 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Instrumentation;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -56,6 +60,7 @@ import android.widget.PopupWindow;
import android.widget.TextView;
import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ActivityScenario;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
@@ -89,6 +94,8 @@ public class ListPopupWindowTest {
private AdapterView.OnItemClickListener mItemClickListener;
+ private ActivityScenario<ListPopupWindowCtsActivity> mScenario;
+
/**
* Item click listener that dismisses our <code>ListPopupWindow</code> when any item
* is clicked. Note that this needs to be a separate class that is also protected (not
@@ -500,7 +507,7 @@ public class ListPopupWindowTest {
final ListView popupListView = mPopupWindow.getListView();
final Rect rect = new Rect();
mPopupWindow.getBackground().getPadding(rect);
- CtsTouchUtils.emulateTapOnView(instrumentation, mActivityRule, popupListView,
+ CtsTouchUtils.emulateTapOnView(instrumentation, null, popupListView,
-rect.left - 20, popupListView.getHeight() / 2);
// At this point our popup should not be showing and should have notified its
@@ -515,6 +522,21 @@ public class ListPopupWindowTest {
@Test
public void testDismissalOutsideNonModal() {
+ // Close the activity that was launched by setup
+ mActivityRule.finishActivity();
+
+ // Launch activity in fullscreen windowing mode
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(mInstrumentation.getTargetContext(), ListPopupWindowCtsActivity.class);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ mScenario = ActivityScenario.launch(intent, options.toBundle());
+ mScenario.onActivity(activity -> {
+ mActivity = activity;
+ mActivity.getApplicationInfo().setEnableOnBackInvokedCallback(false);
+ });
+
verifyDismissalViaTouch(false);
}
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
index bca2bc72cfa..50ee3b1f4b8 100755
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -403,34 +403,6 @@ public class SpinnerTest {
TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
false, Color.BLUE, 1, true);
- waitForHasFocusMS(SPINNER_HAS_FOCUS_DELAY_MS);
- // Dismiss the popup with the emulated back key
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- // Verify that we're not showing the popup
- PollingCheck.waitFor(() -> !mSpinnerDropdownMode.isPopupShowing());
-
- // Set yellow background on the popup
- mActivityRule.runOnUiThread(() ->
- mSpinnerDropdownMode.setPopupBackgroundDrawable(
- mActivity.getDrawable(R.drawable.yellow_fill)));
-
- // Use instrumentation to emulate a tap on the spinner to bring down its popup
- WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSpinnerDropdownMode, () -> {
- mSpinnerDropdownMode.performClick();
- });
- // Verify that we're showing the popup
- PollingCheck.waitFor(() -> mSpinnerDropdownMode.isPopupShowing());
- // And test its fill
- dropDownBackground = mSpinnerDropdownMode.getPopupBackground();
- TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
- dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
- false, Color.YELLOW, 1, true);
-
- waitForHasFocusMS(SPINNER_HAS_FOCUS_DELAY_MS);
- // Dismiss the popup with the emulated escape key
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ESCAPE);
- // Verify that we're not showing the popup
- PollingCheck.waitFor(() -> !mSpinnerDropdownMode.isPopupShowing());
}
@Test
@@ -450,38 +422,5 @@ public class SpinnerTest {
PollingCheck.waitFor(() -> mSpinnerDialogMode.isPopupShowing());
// And test that getPopupBackground returns null
assertNull(mSpinnerDialogMode.getPopupBackground());
-
- // Dismiss the popup with the emulated back key
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- // Verify that we're not showing the popup
- PollingCheck.waitFor(() -> !mSpinnerDialogMode.isPopupShowing());
-
- // Set yellow background on the popup
- mActivityRule.runOnUiThread(() ->
- mSpinnerDialogMode.setPopupBackgroundDrawable(
- mActivity.getDrawable(R.drawable.yellow_fill)));
-
- // Use instrumentation to emulate a tap on the spinner to bring down its popup
- WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mSpinnerDialogMode, () -> {
- mSpinnerDialogMode.performClick();
- });
- // Verify that we're showing the popup
- PollingCheck.waitFor(() -> mSpinnerDialogMode.isPopupShowing());
- // And test that getPopupBackground returns null
- assertNull(mSpinnerDialogMode.getPopupBackground());
-
- // Use emulated escape key to close popup
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ESCAPE);
- // Verify that we're not showing the popup
- PollingCheck.waitFor(() -> !mSpinnerDropdownMode.isPopupShowing());
- }
-
- private void waitForHasFocusMS(int milliseconds) {
- try {
- Thread.sleep(milliseconds);
- } catch (InterruptedException e) {
- fail("unexpected InterruptedException : "+ e);
- }
-
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 38dedf66091..ca8dfb043cd 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -64,6 +64,7 @@ import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.TestUtils;
@@ -989,7 +990,9 @@ public class ToastTest {
* us to wait a given amount of time to test that the limit has been enforced/lifted.
*/
@Test
+ @ApiTest(apis = {"android.widget.Toast#show"})
public void testRateLimitingToastsWhenInBackground() throws Throwable {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
// enable rate limiting to test it
SystemUtil.runWithShellPermissionIdentity(() -> mNotificationManager
.setToastRateLimitingEnabled(true));
@@ -1051,7 +1054,9 @@ public class ToastTest {
}
@Test
+ @ApiTest(apis = {"android.widget.Toast#show"})
public void testAppWithUnlimitedToastsPermissionCanPostUnlimitedToasts() throws Throwable {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
// enable rate limiting to test it
SystemUtil.runWithShellPermissionIdentity(() -> mNotificationManager
.setToastRateLimitingEnabled(true));
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 864b31c6bf2..90941ab8788 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -1884,6 +1884,7 @@ public class WifiManagerTest extends WifiJUnit3TestBase {
TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock);
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
setWifiEnabled(false);
+ Thread.sleep(TEST_WAIT_DURATION_MS);
boolean wifiEnabled = mWifiManager.isWifiEnabled();
try {
uiAutomation.adoptShellPermissionIdentity();
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 3d57a11d0f7..39292355dbc 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -99,6 +99,9 @@ JAR_DIR=${CTS_ROOT}/android-cts/tools
for JAR in ${JAR_DIR}/*.jar; do
JAR_PATH=${JAR_PATH}:${JAR}
done
+# Move 'tradefed.jar' to the front of the jar path
+TRADEFED_JAR=":${JAR_DIR}/tradefed.jar"
+JAR_PATH="${TRADEFED_JAR}${JAR_PATH/$TRADEFED_JAR}"
JAR_PATH=${JAR_PATH:1} # Strip off leading ':'
# load any shared libraries for host-side executables
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 4f6360f27ca..39e5c1f7bcd 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -314,4 +314,9 @@
<!-- b/266101051-->
<option name="compatibility:exclude-filter" value="CtsGameServiceTestCases" />
+
+ <!--- b/260389884 -->
+ <option name="compatibility:exclude-filter" value="CtsGameManagerTestCases android.gamemanager.cts.GameManagerTest#testSetGameStatePerformanceMode" />
+ <option name="compatibility:exclude-filter" value="CtsGameManagerTestCases android.gamemanager.cts.GameManagerTest#testSetGameStatePerformanceMode_withParams" />
+ <option name="compatibility:exclude-filter" value="CtsGameManagerTestCases android.gamemanager.cts.GameManagerTest#testSetGameStateStandardMode" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-system.xml b/tools/cts-tradefed/res/config/cts-system.xml
new file mode 100644
index 00000000000..530fe79beb6
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-system.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs a subset of CTS tests when vendor image is not changed">
+ <option name="plan" value="cts-system" />
+ <option name="result-attribute" key="system" value="1" />
+
+ <include name="cts" />
+
+ <!-- dEQP tests to be included in this plan-->
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-EGL.*" />
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-VK.wsi.*" />
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES2.functional.prerequisite#*" />
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES3.functional.prerequisite#*" />
+ <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-VK.api.smoke#*" />
+
+</configuration> \ No newline at end of file