summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-11-04 00:16:33 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-11-04 00:16:33 +0000
commit25e75775d8a849f2f1dd0e4204419721b9a4e55e (patch)
treec95cc031fcd4b425a856806581313bc1eed3cf96
parentb56382f891a5b1d2c7e9a8c13e3ab1071dbdc04b (diff)
parent61669df01b1d38acb204585f919ccd7faac4c711 (diff)
downloadcts-android13-mainline-ipsec-release.tar.gz
Snap for 9254005 from 61669df01b1d38acb204585f919ccd7faac4c711 to mainline-ipsec-releaseaml_ips_331910010aml_ips_331312000aml_ips_331310000android13-mainline-ipsec-release
Change-Id: Ic6cb2c6d44e0f4fc4045d8d57240bb8d7ae99889
-rw-r--r--apps/PermissionApp/Android.bp2
-rw-r--r--common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java24
-rw-r--r--common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java21
-rw-r--r--common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java14
-rw-r--r--hostsidetests/appcompat/strictjavapackages/Android.bp1
-rw-r--r--hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml1
-rw-r--r--hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java11
-rw-r--r--hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp4
-rw-r--r--hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp4
-rw-r--r--hostsidetests/inputmethodservice/deviceside/ime1/Android.bp1
-rw-r--r--hostsidetests/scopedstorage/Android.bp48
-rw-r--r--hostsidetests/scopedstorage/AndroidTestAppCloning.xml36
-rw-r--r--hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningMediaProviderHostTest.java162
-rw-r--r--hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java33
-rw-r--r--hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java2
-rw-r--r--hostsidetests/scopedstorage/src/android/scopedstorage/cts/AppCloningDeviceTest.java93
-rw-r--r--hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java20
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java43
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java68
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java6
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java4
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java68
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp39
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml26
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml21
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml34
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java148
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java114
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java33
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp39
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml28
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml33
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java124
-rw-r--r--hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java74
-rw-r--r--hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java2
-rw-r--r--tests/PhotoPicker/AndroidManifest.xml16
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java65
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java35
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java6
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java25
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java12
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java96
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java130
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java26
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java43
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java (renamed from tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java)4
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/UiAssertionUtils.java49
-rw-r--r--tests/accessibility/Android.bp2
-rw-r--r--tests/accessibility/AndroidManifest.xml11
-rw-r--r--tests/accessibility/res/values/strings.xml3
-rw-r--r--tests/accessibility/res/xml/no_feedback_accessibilityservice.xml16
-rw-r--r--tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java34
-rw-r--r--tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java29
-rw-r--r--tests/accessibilityservice/Android.bp3
-rw-r--r--tests/accessibilityservice/AndroidManifest.xml2
-rw-r--r--tests/accessibilityservice/AndroidTest.xml5
-rw-r--r--tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java74
-rw-r--r--tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp24
-rw-r--r--tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml41
-rw-r--r--tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml17
-rw-r--r--tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java29
-rw-r--r--tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java29
-rw-r--r--tests/backup/AndroidTest.xml1
-rw-r--r--tests/backup/TEST_MAPPING10
-rw-r--r--tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java18
-rw-r--r--tests/media/AndroidTest.xml8
-rw-r--r--tests/media/src/android/mediav2/cts/CodecTestBase.java3
-rw-r--r--tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java2
-rw-r--r--tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java7
-rw-r--r--tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java8
-rw-r--r--tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java21
-rw-r--r--tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java10
-rw-r--r--tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java8
-rw-r--r--tests/tests/mediastress/AndroidTest.xml8
-rw-r--r--tests/tests/permission/Android.bp2
-rw-r--r--tests/tests/permission/AndroidTest.xml2
-rw-r--r--tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp32
-rw-r--r--tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml24
-rw-r--r--tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp32
-rw-r--r--tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml24
-rw-r--r--tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java4
-rw-r--r--tests/tests/permission/src/android/permission/cts/NotificationListenerUtils.kt38
-rw-r--r--tests/tests/permission/src/android/permission/cts/NotificationUtils.kt120
-rw-r--r--tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt64
-rw-r--r--tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt42
-rw-r--r--tests/tests/security/Android.bp129
-rw-r--r--tests/tests/security/AndroidManifest.xml27
-rw-r--r--tests/tests/security/AndroidTest.xml15
-rw-r--r--tests/tests/security/res/raw/cve_2022_25669.3gpbin0 -> 194103 bytes
-rw-r--r--tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml20
-rw-r--r--tests/tests/security/res/xml/syncadapter.xml19
-rw-r--r--tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java112
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java120
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java56
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java79
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java112
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java33
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java71
-rw-r--r--tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java50
-rw-r--r--tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt813
-rw-r--r--tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt102
-rw-r--r--tests/tests/security/src/android/security/cts/StagefrightTest.java12
-rw-r--r--tests/tests/security/src/android/security/cts/WallpaperManagerTest.java4
-rw-r--r--tests/tests/security/test-cert-1.pk8bin0 -> 138 bytes
-rw-r--r--tests/tests/security/test-cert-1.x509.pem10
-rw-r--r--tests/tests/security/test-cert-2.pk8bin0 -> 138 bytes
-rw-r--r--tests/tests/security/test-cert-2.x509.pem10
-rw-r--r--tests/tests/security/test-cert-3.pk8bin0 -> 138 bytes
-rw-r--r--tests/tests/security/test-cert-3.x509.pem10
-rw-r--r--tests/tests/security/test-cert-4.pk8bin0 -> 138 bytes
-rw-r--r--tests/tests/security/test-cert-4.x509.pem10
-rw-r--r--tests/tests/security/test-cert-with-1-2-4-in-rotation-historybin0 -> 1361 bytes
-rw-r--r--tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml30
-rw-r--r--tests/tests/webkit/Android.bp1
-rwxr-xr-xtests/tests/webkit/src/android/webkit/cts/WebViewTest.java2189
-rw-r--r--tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java6
-rw-r--r--tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java2
-rw-r--r--tests/uwb/Android.bp1
-rw-r--r--tests/uwb/src/android/uwb/cts/UwbManagerTest.java340
-rw-r--r--tests/uwb/src/android/uwb/cts/UwbTestUtils.java8
-rw-r--r--tools/cts-media-preparer-app/Android.bp2
166 files changed, 5627 insertions, 1641 deletions
diff --git a/apps/PermissionApp/Android.bp b/apps/PermissionApp/Android.bp
index 70c7d672b0c..df62a77e5fa 100644
--- a/apps/PermissionApp/Android.bp
+++ b/apps/PermissionApp/Android.bp
@@ -30,6 +30,6 @@ android_test_helper_app {
"arcts",
"cts",
"general-tests",
- "mts",
+ "mts-permission",
],
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
index f8b24fdd4d9..cdec8961275 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
@@ -481,7 +481,7 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
Context context = getInstrumentation().getTargetContext();
for (PackageInfo pkg : packageInfos.values()) {
- int targetSdk = pkg.applicationInfo.targetSandboxVersion;
+ int targetSdk = pkg.applicationInfo.targetSdkVersion;
int uid = pkg.applicationInfo.uid;
for (String permission : pkg.requestedPermissions) {
@@ -571,7 +571,7 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
for (String requestedPermission : packageInfo.requestedPermissions) {
if (pregrantedPerms.contains(requestedPermission)) {
- uidState.addGrantedPermission(packageInfo.packageName, reason, requestedPermission,
+ uidState.addGrantedPermission(packageInfo, reason, requestedPermission,
fixed);
}
}
@@ -815,22 +815,16 @@ public abstract class BaseDefaultPermissionGrantPolicyTest extends BusinessLogic
}
}
- public void addGrantedPermission(String packageName, String reason, String permission,
+ public void addGrantedPermission(PackageInfo packageInfo, String reason, String permission,
FixedState fixed) {
- Context context = getInstrumentation().getTargetContext();
+ String packageName = packageInfo.packageName;
+ int targetSdk = packageInfo.applicationInfo.targetSdkVersion;
// Add permissions split off from the permission to granted
- try {
- PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
- int targetSdk = info.applicationInfo.targetSdkVersion;
-
- for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
- mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
- : reason + " (split from " + permission + ")", extendedPerm,
- fixed, false);
- }
- } catch (PackageManager.NameNotFoundException e) {
- // ignore
+ for (String extendedPerm : extendBySplitPermissions(permission, targetSdk)) {
+ mergeGrantedPermission(packageName, extendedPerm.equals(permission) ? reason
+ : reason + " (split from " + permission + ")", extendedPerm,
+ fixed, false);
}
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index 488c73faa09..c3b6900c64e 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -1532,6 +1532,27 @@ public class MediaUtils {
return false;
}
+ /**
+ * Function to identify if the device is a cuttlefish instance
+ */
+ public static boolean onCuttlefish() throws IOException {
+ String device = SystemProperties.get("ro.product.device", "");
+ String model = SystemProperties.get("ro.product.model", "");
+ String name = SystemProperties.get("ro.product.name", "");
+
+ // Return true for cuttlefish instances
+ if (!device.startsWith("vsoc_")) {
+ return false;
+ }
+ if (!model.startsWith("Cuttlefish ")) {
+ return false;
+ }
+ if (name.startsWith("cf_") || name.startsWith("aosp_cf_")) {
+ return true;
+ }
+ return false;
+ }
+
/*
* -------------------------------------- END --------------------------------------
*/
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index 3f42e32f5f5..a9543c246ab 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull;
import android.graphics.Rect;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.StaleObjectException;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -28,6 +29,7 @@ import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.TypedValue;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
@@ -37,6 +39,8 @@ import java.util.regex.Pattern;
public class UiAutomatorUtils {
private UiAutomatorUtils() {}
+ private static final String LOG_TAG = "UiAutomatorUtils";
+
/** Default swipe deadzone percentage. See {@link UiScrollable}. */
private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1;
@@ -86,7 +90,15 @@ public class UiAutomatorUtils {
final int minViewHeightPx = convertDpToPx(MIN_VIEW_HEIGHT_DP);
while (view == null && start + timeoutMs > System.currentTimeMillis()) {
- view = getUiDevice().wait(Until.findObject(selector), 1000);
+ try {
+ view = getUiDevice().wait(Until.findObject(selector), 1000);
+ } catch (StaleObjectException exception) {
+ // UiDevice.wait() may cause StaleObjectException if the {@link View} attached to
+ // UiObject2 is no longer in the view tree.
+ Log.v(LOG_TAG, "UiObject2 view is no longer in the view tree.", exception);
+ getUiDevice().waitForIdle();
+ continue;
+ }
if (view == null || view.getVisibleBounds().height() < minViewHeightPx) {
final double deadZone = !(FeatureUtil.isWatch() || FeatureUtil.isTV())
diff --git a/hostsidetests/appcompat/strictjavapackages/Android.bp b/hostsidetests/appcompat/strictjavapackages/Android.bp
index 272be12119d..2656bbc1363 100644
--- a/hostsidetests/appcompat/strictjavapackages/Android.bp
+++ b/hostsidetests/appcompat/strictjavapackages/Android.bp
@@ -27,6 +27,7 @@ java_test_host {
],
static_libs: [
"compat-classpaths-testing",
+ "modules-utils-build-testing",
"dexlib2-no-guava-no-cli",
],
// tag this module as a cts test artifact
diff --git a/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml b/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml
index e61058125cb..f76eab4bc9b 100644
--- a/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml
+++ b/hostsidetests/appcompat/strictjavapackages/app/AndroidManifest.xml
@@ -20,6 +20,7 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner" />
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 da41f95ef30..6b1f6fc33b7 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -236,6 +236,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
"Landroid/app/sdksandbox/ILoadSdkCallback;",
"Landroid/app/sdksandbox/IRequestSurfacePackageCallback;",
"Landroid/app/sdksandbox/ISdkSandboxManager;",
+ "Landroid/app/sdksandbox/ISdkSandboxLifecycleCallback;",
"Landroid/app/sdksandbox/ISdkSandboxProcessDeathCallback;",
"Landroid/app/sdksandbox/ISendDataCallback;",
"Landroid/app/sdksandbox/ISharedPreferencesSyncCallback;",
@@ -737,6 +738,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
"Lcom/android/sdksandbox/IDataReceivedCallback;",
"Lcom/android/sdksandbox/ILoadSdkInSandboxCallback;",
"Lcom/android/sdksandbox/IRequestSurfacePackageFromSdkCallback;",
+ "Lcom/android/sdksandbox/ISdkSandboxDisabledCallback;",
"Lcom/android/sdksandbox/ISdkSandboxManagerToSdkSandboxCallback;",
"Lcom/android/sdksandbox/ISdkSandboxService;",
"Lcom/android/sdksandbox/SandboxLatencyInfo-IA;",
@@ -1008,13 +1010,14 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
/**
* Ensure that no apk-in-apex bundles classes that could be eclipsed by jars in
- * BOOTCLASSPATH, SYSTEMSERVERCLASSPATH.
+ * BOOTCLASSPATH.
*/
@Test
public void testApkInApex_nonClasspathClasses() throws Exception {
HashMultimap<String, Multimap<String, String>> perApkClasspathDuplicates =
HashMultimap.create();
Arrays.stream(collectApkInApexPaths())
+ .filter(apk -> apk != null && !apk.isEmpty())
.parallel()
.forEach(apk -> {
File apkFile = null;
@@ -1038,9 +1041,12 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
className -> !burndownClasses.contains(className)
// TODO: b/225341497
&& !className.equals("Landroidx/annotation/Keep;"));
+ final Multimap<String, String> bcpOnlyDuplicates =
+ Multimaps.filterKeys(filteredDuplicates,
+ sBootclasspathJars::contains);
if (!filteredDuplicates.isEmpty()) {
synchronized (perApkClasspathDuplicates) {
- perApkClasspathDuplicates.put(apk, filteredDuplicates);
+ perApkClasspathDuplicates.put(apk, bcpOnlyDuplicates);
}
}
} catch (Exception e) {
@@ -1082,6 +1088,7 @@ public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
+ "bootclasspath. Please use alternatives provided by the platform instead. "
+ "See go/androidx-api-guidelines#module-naming.")
.that(sJarsToClasses.entries().stream()
+ .filter(e -> e.getKey().endsWith(".jar"))
.filter(e -> e.getValue().startsWith("Landroidx/"))
.filter(e -> !isLegacyAndroidxDependency(
LegacyExemptAndroidxSharedLibsNamesToClasses, e.getKey(), e.getValue()))
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index ed22bab07b6..d6b736d5198 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -38,7 +38,9 @@ android_test_helper_app {
test_suites: [
"cts",
"general-tests",
- "mts",
+ "mts-documentsui",
+ "mts-mainline-infra",
+ "mts-mediaprovider",
"sts",
],
certificate: ":cts-testkey2",
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index b42c9ac5d8c..723d0632057 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -33,7 +33,9 @@ android_test_helper_app {
test_suites: [
"cts",
"general-tests",
- "mts",
+ "mts-documentsui",
+ "mts-mainline-infra",
+ "mts-mediaprovider",
"sts",
],
certificate: ":cts-testkey1",
diff --git a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
index 8c59b536a96..1608365815c 100644
--- a/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
+++ b/hostsidetests/inputmethodservice/deviceside/ime1/Android.bp
@@ -28,6 +28,7 @@ android_test_helper_app {
test_suites: [
"cts",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
min_sdk_version: "19",
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index 0e2a887bc40..d5052b903db 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -238,6 +238,29 @@ android_test_helper_app {
}
android_test_helper_app {
+ name: "AppCloningDeviceTest",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "truth-prebuilt",
+ "cts-scopedstorage-lib",
+ "modules-utils-build_system",
+ ],
+ compile_multilib: "both",
+ test_suites: [
+ "general-tests",
+ "mts-mediaprovider",
+ "cts",
+ ],
+ sdk_version: "test_current",
+ target_sdk_version: "33",
+ min_sdk_version: "29",
+ java_resources: [
+ ":CtsScopedStorageTestAppB",
+ ],
+}
+
+android_test_helper_app {
name: "LegacyStorageTest",
manifest: "legacy/AndroidManifest.xml",
srcs: ["legacy/src/**/*.java"],
@@ -318,6 +341,31 @@ java_test_host {
}
java_test_host {
+ name: "CtsAppCloningMediaProviderHostTest",
+ srcs: ["host/src/**/*.java"],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "testng",
+ ],
+ static_libs: [
+ "modules-utils-build-testing",
+ "compatibility-host-util",
+ ],
+ test_suites: [
+ "general-tests",
+ "mts-mediaprovider",
+ "cts",
+ ],
+ test_config: "AndroidTestAppCloning.xml",
+ per_testcase_directory: true,
+ data: [
+ ":CtsScopedStorageTestAppB",
+ ":AppCloningDeviceTest",
+ ],
+}
+
+java_test_host {
name: "GtsPreserveLegacyStorageHostTest",
srcs: [
"host/src/android/scopedstorage/cts/host/PreserveLegacyStorageHostTest.java",
diff --git a/hostsidetests/scopedstorage/AndroidTestAppCloning.xml b/hostsidetests/scopedstorage/AndroidTestAppCloning.xml
new file mode 100644
index 00000000000..665db66947f
--- /dev/null
+++ b/hostsidetests/scopedstorage/AndroidTestAppCloning.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="External storage host test Test for App cloning use case">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <option
+ name="config-descriptor:metadata"
+ key="mainline-param"
+ value="com.google.android.mediaprovider.apex" />
+
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="android.scopedstorage.cts.host.AppCloningMediaProviderHostTest" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.mediaprovider" />
+ </object>
+</configuration>
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningMediaProviderHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningMediaProviderHostTest.java
new file mode 100644
index 00000000000..77086f0d356
--- /dev/null
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/AppCloningMediaProviderHostTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.scopedstorage.cts.host;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.TestInformation;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
+import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+import com.android.tradefed.util.CommandResult;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+@AppModeFull
+public class AppCloningMediaProviderHostTest extends BaseHostTestCase{
+
+ protected static final String DEVICE_TEST_APP_PACKAGE = "android.scopedstorage.cts";
+ protected static final String DEVICE_TEST_APP = "AppCloningDeviceTest.apk";
+ private static final String DEVICE_TEST_CLASS = DEVICE_TEST_APP_PACKAGE
+ + ".AppCloningDeviceTest";
+ // This app performs the File Creation and Read operations from the Device.
+ protected static final String SCOPED_STORAGE_TEST_APP_B_APK = "CtsScopedStorageTestAppB.apk";
+
+ private static final int CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS = 20000;
+ private static final long DEFAULT_INSTRUMENTATION_TIMEOUT_MS = 600_000;
+ private static final String EXTERNAL_STORAGE_PATH = "/storage/emulated/%d/";
+ private static final String CURRENT_USER_ID = "currentUserId";
+ private static final String FILE_TO_BE_CREATED = "fileToBeCreated";
+ private static final String FILE_EXPECTED_TO_BE_PRESENT = "fileExpectedToBePresent";
+ private static final String FILE_NOT_EXPECTED_TO_BE_PRESENT = "fileNotExpectedToBePresent";
+ /**
+ * Provide different name to Files being created, on each execution of the test, so that
+ * flakiness from previously existing files can be avoided.
+ */
+ private static final String NONCE = String.valueOf(System.nanoTime());
+ private static String sCloneUserId;
+
+ @BeforeClassWithInfo
+ public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
+ final ITestDevice sDevice = testInfo.getDevice();
+ assertThat(sDevice).isNotNull();
+
+ setDevice(sDevice);
+
+ assumeTrue("Device doesn't support multiple users", supportsMultipleUsers());
+ assumeFalse("Device is in headless system user mode", isHeadlessSystemUserMode());
+ assumeTrue(isAtLeastS());
+ assumeFalse("Device uses sdcardfs", usesSdcardFs());
+
+ // create clone user
+ String output = sDevice.executeShellCommand(
+ "pm create-user --profileOf 0 --user-type android.os.usertype.profile.CLONE "
+ + "testUser");
+ sCloneUserId = output.substring(output.lastIndexOf(' ') + 1).replaceAll("[^0-9]",
+ "");
+ assertThat(sCloneUserId).isNotEmpty();
+ // start clone user
+ CommandResult out = sDevice.executeShellV2Command("am start-user -w " + sCloneUserId);
+ assertThat(isSuccessful(out)).isTrue();
+
+ Integer mCloneUserIdInt = Integer.parseInt(sCloneUserId);
+ String sCloneUserStoragePath = String.format(EXTERNAL_STORAGE_PATH,
+ Integer.parseInt(sCloneUserId));
+ // Check that the clone user directories have been created
+ eventually(() -> sDevice.doesFileExist(sCloneUserStoragePath, mCloneUserIdInt),
+ CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS);
+ }
+
+ @AfterClassWithInfo
+ public static void afterClass(TestInformation testInfo) throws Exception {
+ if (!supportsMultipleUsers() || isHeadlessSystemUserMode() || !isAtLeastS()
+ || usesSdcardFs()) return;
+ testInfo.getDevice().executeShellCommand("pm remove-user " + sCloneUserId);
+ }
+
+ @Test
+ public void testGetFilesInDirectoryViaMediaProvider() throws Exception {
+ // Install the Device Test App in both the user spaces.
+ installPackage(DEVICE_TEST_APP, "--user all");
+ // Install the Scoped Storage Test App in both the user spaces.
+ installPackage(SCOPED_STORAGE_TEST_APP_B_APK, "--user all");
+
+ int currentUserId = getCurrentUserId();
+ final String fileName = "tmpFileToPush" + NONCE + ".png";
+
+ // We add the file in DCIM directory of User 0.
+ Map<String, String> ownerArgs = new HashMap<>();
+ ownerArgs.put(CURRENT_USER_ID, String.valueOf(currentUserId));
+ ownerArgs.put(FILE_TO_BE_CREATED, fileName);
+ runDeviceTestAsUserInPkgA("testInsertFilesInDirectoryViaMediaProvider",
+ currentUserId, ownerArgs);
+
+ // We add the file in DCIM directory of Cloned User.
+ final String fileNameClonedUser = "tmpFileToPushClonedUser" + NONCE + ".png";
+ Map<String, String> cloneArgs = new HashMap<>();
+ cloneArgs.put(CURRENT_USER_ID, sCloneUserId);
+ cloneArgs.put(FILE_TO_BE_CREATED, fileNameClonedUser);
+ runDeviceTestAsUserInPkgA("testInsertFilesInDirectoryViaMediaProvider",
+ Integer.parseInt(sCloneUserId), cloneArgs);
+
+ // Querying as user 0 should enlist the file(s) created by user 0 only.
+ Map<String, String> listFilesArgs = new HashMap<>();
+ listFilesArgs.put(CURRENT_USER_ID, String.valueOf(currentUserId));
+ listFilesArgs.put(FILE_EXPECTED_TO_BE_PRESENT, fileName);
+ listFilesArgs.put(FILE_NOT_EXPECTED_TO_BE_PRESENT, fileNameClonedUser);
+ runDeviceTestAsUserInPkgA("testGetFilesInDirectoryViaMediaProviderRespectsUserId",
+ currentUserId, listFilesArgs);
+
+ // Querying as cloned user should enlist the file(s) created by cloned user only.
+ listFilesArgs.put(CURRENT_USER_ID, sCloneUserId);
+ listFilesArgs.put(FILE_EXPECTED_TO_BE_PRESENT, fileNameClonedUser);
+ listFilesArgs.put(FILE_NOT_EXPECTED_TO_BE_PRESENT, fileName);
+ runDeviceTestAsUserInPkgA("testGetFilesInDirectoryViaMediaProviderRespectsUserId",
+ Integer.parseInt(sCloneUserId), listFilesArgs);
+ }
+
+ protected void runDeviceTestAsUserInPkgA(@Nonnull String testMethod, int userId,
+ @Nonnull Map<String, String> args) throws Exception {
+ DeviceTestRunOptions deviceTestRunOptions =
+ new DeviceTestRunOptions(DEVICE_TEST_APP_PACKAGE)
+ .setDevice(getDevice())
+ .setTestClassName(DEVICE_TEST_CLASS)
+ .setTestMethodName(testMethod)
+ .setMaxInstrumentationTimeoutMs(DEFAULT_INSTRUMENTATION_TIMEOUT_MS)
+ .setUserId(userId);
+ for (Map.Entry<String, String> entry : args.entrySet()) {
+ deviceTestRunOptions.addInstrumentationArg(entry.getKey(), entry.getValue());
+ }
+ assertWithMessage(testMethod + " failed").that(
+ runDeviceTests(deviceTestRunOptions)).isTrue();
+ }
+}
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
index 5587a88465d..6bc732860b5 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/BaseHostTestCase.java
@@ -16,6 +16,8 @@
package android.scopedstorage.cts.host;
+import static com.google.common.truth.Truth.assertThat;
+
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.NativeDevice;
@@ -28,6 +30,11 @@ import com.android.tradefed.util.CommandStatus;
abstract class BaseHostTestCase extends BaseHostJUnit4Test {
private int mCurrentUserId = NativeDevice.INVALID_USER_ID;
private static final String ERROR_MESSAGE_TAG = "[ERROR]";
+ protected static ITestDevice sDevice = null;
+
+ protected static void setDevice(ITestDevice device) {
+ sDevice = device;
+ }
protected String executeShellCommand(String cmd, Object... args) throws Exception {
return getDevice().executeShellCommand(String.format(cmd, args));
@@ -42,14 +49,14 @@ abstract class BaseHostTestCase extends BaseHostJUnit4Test {
}
// TODO (b/174775905) remove after exposing the check from ITestDevice.
- protected boolean isHeadlessSystemUserMode() throws DeviceNotAvailableException {
- String result = getDevice()
+ protected static boolean isHeadlessSystemUserMode() throws DeviceNotAvailableException {
+ String result = sDevice
.executeShellCommand("getprop ro.fw.mu.headless_system_user").trim();
return "true".equalsIgnoreCase(result);
}
- protected boolean isAtLeastS() throws DeviceNotAvailableException {
- return getDevice().getApiLevel() >= 31 /* BUILD.VERSION_CODES.S */;
+ protected static boolean isAtLeastS() throws DeviceNotAvailableException {
+ return sDevice.getApiLevel() >= 31 /* BUILD.VERSION_CODES.S */;
}
protected static void eventually(ThrowingRunnable r, long timeoutMillis) {
@@ -79,7 +86,7 @@ abstract class BaseHostTestCase extends BaseHostJUnit4Test {
return mCurrentUserId;
}
- protected boolean isSuccessful(CommandResult result) {
+ protected static boolean isSuccessful(CommandResult result) {
if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
return false;
}
@@ -91,6 +98,22 @@ abstract class BaseHostTestCase extends BaseHostJUnit4Test {
return (stderr == null || stderr.trim().isEmpty());
}
+ protected static boolean supportsMultipleUsers() throws DeviceNotAvailableException {
+ return sDevice.getMaxNumberOfUsersSupported() > 1;
+ }
+
+ protected static boolean usesSdcardFs() throws Exception {
+ CommandResult out = sDevice.executeShellV2Command("cat /proc/mounts");
+ assertThat(isSuccessful(out)).isTrue();
+ for (String line : out.getStdout().split("\n")) {
+ String[] split = line.split(" ");
+ if (split.length >= 3 && split[2].equals("sdcardfs")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void setCurrentUserId() throws Exception {
if (mCurrentUserId != NativeDevice.INVALID_USER_ID) return;
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index c7887f82040..7590679b3aa 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -26,6 +26,7 @@ import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -310,6 +311,7 @@ public class ScopedStorageHostTest extends BaseHostTestCase {
}
@Test
+ @Ignore("b/247099819")
public void testClearPackageData() throws Exception {
grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
try {
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/AppCloningDeviceTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/AppCloningDeviceTest.java
new file mode 100644
index 00000000000..6df4c8fb68b
--- /dev/null
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/AppCloningDeviceTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.scopedstorage.cts;
+
+import static android.scopedstorage.cts.lib.TestUtils.canOpenFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.createFileAs;
+import static android.scopedstorage.cts.lib.TestUtils.listAs;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.cts.install.lib.TestApp;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+public class AppCloningDeviceTest {
+
+ private static final String EMPTY_STRING = "";
+ private static final String EXTERNAL_STORAGE_DCIM_PATH = "/storage/emulated/%d/DCIM";
+
+ // An app with no permissions
+ private static final TestApp APP_B_NO_PERMS = new TestApp("TestAppB",
+ "android.scopedstorage.cts.testapp.B.noperms", 1, false,
+ "CtsScopedStorageTestAppB.apk");
+
+ @Test
+ public void testInsertFilesInDirectoryViaMediaProvider() throws Exception {
+ String dirPath = String.format(EXTERNAL_STORAGE_DCIM_PATH,
+ Integer.parseInt(getCurrentUserId()));
+ final File dir = new File(dirPath);
+ assertThat(dir.exists()).isTrue();
+ final File file = new File(dir, getFileToBeCreatedName());
+ assertThat(createFileAs(APP_B_NO_PERMS, file.getPath())).isTrue();
+ assertThat(canOpenFileAs(APP_B_NO_PERMS, file, true)).isTrue();
+ assertThat(listAs(APP_B_NO_PERMS, dir.getPath())).contains(file.getName());
+ }
+
+ @Test
+ public void testGetFilesInDirectoryViaMediaProviderRespectsUserId() throws Exception {
+ String dirPath = String.format(EXTERNAL_STORAGE_DCIM_PATH,
+ Integer.parseInt(getCurrentUserId()));
+ final File dir = new File(dirPath);
+ assertThat(dir.exists()).isTrue();
+ final File expectedFile = new File(dir, getFileToBeExpectedName());
+ assertThat(listAs(APP_B_NO_PERMS, dir.getPath())).contains(expectedFile.getName());
+ final File notExpectedFile = new File(dir, getFileNotToBeExpectedName());
+ assertThat(listAs(APP_B_NO_PERMS, dir.getPath())).doesNotContain(notExpectedFile.getName());
+ }
+
+ private String getTestArgumentValueForGivenKey(String testArgumentKey) {
+ final Bundle testArguments = InstrumentationRegistry.getArguments();
+ String testArgumentValue = testArguments.getString(testArgumentKey, EMPTY_STRING);
+ return testArgumentValue;
+ }
+
+ private String getCurrentUserId() {
+ return getTestArgumentValueForGivenKey("currentUserId");
+ }
+
+ private String getFileToBeCreatedName() {
+ return getTestArgumentValueForGivenKey("fileToBeCreated");
+ }
+
+ private String getFileToBeExpectedName() {
+ return getTestArgumentValueForGivenKey("fileExpectedToBePresent");
+ }
+
+ private String getFileNotToBeExpectedName() {
+ return getTestArgumentValueForGivenKey("fileNotExpectedToBePresent");
+ }
+}
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 1bb701bcba0..253a7b88e07 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -1151,22 +1151,24 @@ public class ScopedStorageTest {
executeShellCommand("pm clear --user " + getCurrentUser() + " " + testAppPackageName);
- // Wait a max of 5 seconds for the cleaning after "pm clear" command to complete.
+ // Wait a max of 10 seconds for the cleaning after "pm clear" command to complete.
int i = 0;
- while(i < 10 && getFileRowIdFromDatabase(fileToBeDeleted) != -1
+ while (i < 20 && getFileRowIdFromDatabase(fileToBeDeleted) != -1
&& getFileRowIdFromDatabase(nestedFileToBeDeleted) != -1) {
Thread.sleep(500);
i++;
}
-
- assertThat(getFileOwnerPackageFromDatabase(fileToRemain)).isNull();
- assertThat(getFileRowIdFromDatabase(fileToRemain)).isNotEqualTo(-1);
-
- assertThat(getFileOwnerPackageFromDatabase(fileToBeDeleted)).isNull();
assertThat(getFileRowIdFromDatabase(fileToBeDeleted)).isEqualTo(-1);
-
- assertThat(getFileOwnerPackageFromDatabase(nestedFileToBeDeleted)).isNull();
assertThat(getFileRowIdFromDatabase(nestedFileToBeDeleted)).isEqualTo(-1);
+
+ // Poll for package name to be cleared for existing files
+ i = 0;
+ while (i < 20 && getFileOwnerPackageFromDatabase(fileToRemain) != null) {
+ Thread.sleep(500);
+ i++;
+ }
+ assertThat(getFileRowIdFromDatabase(fileToRemain)).isNotEqualTo(-1);
+ assertThat(getFileOwnerPackageFromDatabase(fileToRemain)).isNull();
} finally {
deleteFilesAs(APP_B_NO_PERMS, fileToRemain);
deleteFilesAs(APP_B_NO_PERMS, fileToBeDeleted);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 52141c668ef..bea2bd82ce4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -47,7 +47,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -258,48 +257,6 @@ public class AdbUtils {
}
/**
- * Enables malloc debug on a given process.
- *
- * @param processName the name of the process to run with libc malloc debug
- * @param device the device to use
- * @return true if enabling malloc debug succeeded
- */
- public static boolean enableLibcMallocDebug(String processName, ITestDevice device) throws Exception {
- device.executeShellCommand("setprop libc.debug.malloc.program " + processName);
- device.executeShellCommand("setprop libc.debug.malloc.options \"backtrace guard\"");
- /**
- * The pidof command is being avoided because it does not exist on versions before M, and
- * it behaves differently between M and N.
- * Also considered was the ps -AoPID,CMDLINE command, but ps does not support options on
- * versions before O.
- * The [^]] prefix is being used for the grep command to avoid the case where the output of
- * ps includes the grep command itself.
- */
- String cmdOut = device.executeShellCommand("ps -A | grep '[^]]" + processName + "'");
- /**
- * .hasNextInt() checks if the next token can be parsed as an integer, not if any remaining
- * token is an integer.
- * Example command: $ ps | fgrep mediaserver
- * Out: media 269 1 77016 24416 binder_thr 00f35142ec S /system/bin/mediaserver
- * The second field of the output is the PID, which is needed to restart the process.
- */
- Scanner s = new Scanner(cmdOut).useDelimiter("\\D+");
- if(!s.hasNextInt()) {
- CLog.w("Could not find pid for process: " + processName);
- return false;
- }
-
- String result = device.executeShellCommand("kill -9 " + s.nextInt());
- if(!result.equals("")) {
- CLog.w("Could not restart process: " + processName);
- return false;
- }
-
- TimeUnit.SECONDS.sleep(1);
- return true;
- }
-
- /**
* Pushes and installs an apk to the selected device
*
* @param pathToApk a string path to apk from the /res folder
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
index 1f5caa52834..b461fae5608 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_182810085.java
@@ -22,14 +22,14 @@ import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class Bug_182810085 extends StsExtraBusinessLogicHostTestBase {
+public class Bug_182810085 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_182810085";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-182810085.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
index 75bbd0ac298..f0b6568d57e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183613671.java
@@ -23,10 +23,10 @@ import org.junit.Test;
import org.junit.Before;
import org.junit.runner.RunWith;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183613671 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183613671 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183613671";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183613671.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
index adf6103043a..7b183b387d9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_183963253.java
@@ -25,10 +25,10 @@ import org.junit.Before;
import org.junit.runner.RunWith;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class Bug_183963253 extends StsExtraBusinessLogicHostTestBase {
+public final class Bug_183963253 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.BUG_183963253";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "BUG-183963253.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
index 3aa0474a422..32a1e6ce404 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0015.java
@@ -23,13 +23,13 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0015 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0015 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 139017101)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
index 2bc254e0724..094eaea3d9c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0338.java
@@ -19,7 +19,7 @@ package android.security.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0338 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0338 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 123700107)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
index 27e202cf759..63c812854d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0448.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0448 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2020_0448 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2020-0448.apk";
static final String TEST_PKG = "android.security.cts.CVE_2020_0448";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
index 4b1bc22e33f..9df42ae7cf7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0305.java
@@ -22,7 +22,7 @@ import android.util.Log;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.After;
import org.junit.Assert;
@@ -38,7 +38,7 @@ import org.junit.runner.RunWith;
* collected from the hostside and reported accordingly.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0305 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0305 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0305";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0305.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
index b828d2dcba8..1476e911236 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0315.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0315 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0315 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2021_0315";
@After
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 b3b0f90dce1..57b9a86c191 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0441.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0441 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0441 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2021_0441";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
static final String TEST_APP = "CVE-2021-0441.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java
new file mode 100644
index 00000000000..45a1905b145
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0487.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0487 extends NonRootSecurityTestCase {
+ private static final String TEST_PKG = "android.security.cts.CVE_2021_0487";
+
+ /**
+ * b/174046397
+ * Vulnerable app : CalendarProvider.apk
+ * Vulnerable module : com.android.providers.calendar
+ * Is Play managed : No
+ */
+ @AsbSecurityTest(cveBugId = 174046397)
+ @Test
+ public void testPocCVE_2021_0487() {
+ ITestDevice device = null;
+ try {
+ device = getDevice();
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ /* Install the application */
+ installPackage("CVE-2021-0487.apk");
+
+ AdbUtils.runCommandLine(
+ "pm grant " + TEST_PKG + " android.permission.SYSTEM_ALERT_WINDOW", device);
+ runDeviceTests(TEST_PKG, TEST_PKG + "." + "DeviceTest", "testOverlayButtonPresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // return to home screen
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ } catch (Exception e) {
+ // ignore exceptions here
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
index 30af4725490..7cd63605906 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0523.java
@@ -21,7 +21,7 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0523 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0523 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0523";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0523.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
index 5a7ec8d1c24..f775822dfb6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0586.java
@@ -20,14 +20,14 @@ import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0586 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0586 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0586";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0586.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
index eb74b201862..92c64351de4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0591.java
@@ -21,7 +21,7 @@ import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.RequiresDevice;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Before;
@@ -33,7 +33,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeTrue;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0591 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0591 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0591";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
index 29fd2b39bf2..2e1ddda5360 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0642.java
@@ -19,7 +19,7 @@ package android.security.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0642 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0642 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-0642.apk";
static final String TEST_PKG = "android.security.cts.cve_2021_0642";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
index 26bba4a6d50..15c59efc97e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0685.java
@@ -19,14 +19,14 @@ package android.security.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0685 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0685 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.cve_2021_0685";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0685.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
index bf261fd0eab..01a3c07160b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0691.java
@@ -22,7 +22,7 @@ import android.util.Log;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.log.LogUtil.CLog;
import org.junit.After;
@@ -38,7 +38,7 @@ import static org.hamcrest.CoreMatchers.*;
* Test installs sample app and then tries to overwrite *.apk file
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0691 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0691 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0691";
private static final String TEST_APP = "CVE-2021-0691.apk";
private static final String DEVICE_TMP_DIR = "/data/local/tmp/";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
index 2b7ad1452d2..98deb18e315 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0693.java
@@ -19,13 +19,13 @@ package android.security.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0693 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0693 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0693";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
index fabaf89437a..9225b561ece 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0706.java
@@ -20,13 +20,13 @@ import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0706 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0706";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
index 760c265fe09..d4f6a4517e2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0921.java
@@ -20,7 +20,7 @@ import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.log.LogUtil.CLog;
import org.junit.After;
import org.junit.Assert;
@@ -30,7 +30,7 @@ import org.junit.runner.RunWith;
import static org.junit.Assert.*;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0921 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0921";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0921.apk";
@@ -57,7 +57,7 @@ public class CVE_2021_0921 extends StsExtraBusinessLogicHostTestBase {
getDevice().executeShellCommand("input keyevent KEYCODE_MENU");
//run the test
- Assert.assertTrue(runDeviceTests(TEST_PKG, TEST_CLASS, "test"));
+ runDeviceTests(TEST_PKG, TEST_CLASS, "test");
CLog.i("testRunDeviceTest() end");
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
index cbf108883a1..d83f26a9529 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0928.java
@@ -23,7 +23,7 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -31,7 +31,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0928 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0928 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0928";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0928.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
index ecb6bdd3cd4..833b93aa854 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0953.java
@@ -19,13 +19,13 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0953 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0953 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 184046278)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
index 95c90d4ec4b..847feefa489 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0954.java
@@ -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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0954 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0954 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0954";
@AsbSecurityTest(cveBugId = 143559931)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
index 65934f2741f..b7b0e2bdabc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0965.java
@@ -21,7 +21,7 @@ import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Before;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_0965 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_0965 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_0965";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-0965.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
index 3b12ce5a926..c47ebf119b6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39626.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@ import org.junit.runner.RunWith;
import org.junit.Test;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39626 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39626 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-39626.apk";
static final String TEST_PKG = "android.security.cts.CVE_2021_39626";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
index 444f1a55a60..f75514208c6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39692.java
@@ -23,13 +23,13 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39692 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39692 extends NonRootSecurityTestCase {
@AppModeFull
@AsbSecurityTest(cveBugId = 209611539)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
index acc6a2ed00f..63235ecf78b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39700.java
@@ -23,7 +23,7 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith;
import java.io.File;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39700 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39700 extends NonRootSecurityTestCase {
/**
* b/201645790
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
index f8d6fe6f1d5..5e78a90cd85 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39701.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39701 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39701 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 212286849)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
index cf8a688976b..cf5d47c3dd8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39702.java
@@ -21,14 +21,14 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39702 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39702 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_39702";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2021-39702.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
index af72d3b81de..9aebd152144 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39704.java
@@ -22,13 +22,13 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39704 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39704 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 209965481)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
index cd8afef86e4..ecf096f31d1 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
@@ -21,7 +21,7 @@ import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39706 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 200164168)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
index 2e61b7064a2..e40cea6bbfb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39707.java
@@ -21,7 +21,7 @@ import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39707 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39707 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 200688991)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
index 0ae1efa8e83..d67b4e6d53f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39794.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39794 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39794 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2021-39794-test.apk";
static final String RECEIVER_APP = "CVE-2021-39794-receiver.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
index 4755ddbb229..a427e65169a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39795.java
@@ -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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39795 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39795 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2021_39795";
private static final String DIR_PATH = "/storage/emulated/0/Android/data/CVE-2021-39795-dir";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
index f90cae0c295..07fa92757d9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39796.java
@@ -20,14 +20,14 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39796 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39796 extends NonRootSecurityTestCase {
static final int USER_ID = 0;
static final String TEST_PKG = "android.security.cts.CVE_2021_39796";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
index ee835f50c93..1707ce92429 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
@@ -20,13 +20,13 @@ import android.platform.test.annotations.AsbSecurityTest;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39797 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39797 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 209607104)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
index a55229abe45..f1eaad2edf7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39808.java
@@ -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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39808 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39808 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 209966086)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
index f9520824b26..9745336f8aa 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39810.java
@@ -21,14 +21,14 @@ import 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.testtype.DeviceJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2021_39810 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2021_39810 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 212610736)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
index df8701c9e67..ec4d1977c01 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20004.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20004 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20004 extends NonRootSecurityTestCase {
final static String TEST_PKG = "android.security.cts.CVE_2022_20004_test";
final static String PROVIDER_PKG = "android.security.cts.CVE_2022_20004_provider";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
index 55e6dca25fc..abc94f5837c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
@@ -20,7 +20,7 @@ import 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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20007 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20007 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 211481342)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
index a8256d6bef0..e83f090e94d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20115.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -27,7 +27,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20115 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20115 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2022_20115";
private static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
private static final String TEST_APP = "CVE-2022-20115.apk";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
index 45c6fb137fc..9e5e7eb94b4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20138.java
@@ -18,7 +18,7 @@ package android.security.cts;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -26,7 +26,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20138 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20138 extends NonRootSecurityTestCase {
static final String TEST_APP = "CVE-2022-20138.apk";
static final String TEST_PKG = "android.security.cts.CVE_2022_20138";
static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
index ebfed1a4523..3d31cee17c7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20197.java
@@ -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;
@@ -29,7 +29,7 @@ import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20197 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20197 extends NonRootSecurityTestCase {
private static final String TEST_PKG = "android.security.cts.CVE_2022_20197";
@AsbSecurityTest(cveBugId = 208279300)
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
index f593f204bd6..18d4cdd6f55 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
@@ -21,7 +21,7 @@ import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AsbSecurityTest;
-import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,7 +29,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20223 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20223 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 223578534)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
index 1886a4af4ac..59e7631b287 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20230.java
@@ -20,7 +20,7 @@ import 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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20230 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20230 extends NonRootSecurityTestCase {
public static final int USER_ID = 0;
static final String TEST_APP = "CVE-2022-20230.apk";
static final String TEST_PKG = "android.security.cts.CVE_2022_20230";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
index de245bb06da..8087e692b5f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20347.java
@@ -20,7 +20,7 @@ import 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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20347 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20347 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 228450811)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
index 0f66dfdd87c..df33a31144d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20348.java
@@ -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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20348 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20348 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2022_20348";
public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
index c4f52254d66..f8dcc48de61 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20349.java
@@ -20,7 +20,7 @@ import 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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20349 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20349 extends NonRootSecurityTestCase {
static final String TEST_PKG = "android.security.cts.CVE_2022_20349";
public static final String TEST_DEVICE_ADMIN_RECEIVER = ".PocDeviceAdminReceiver";
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
index e661b4ff4a1..12bb187b47f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20353.java
@@ -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,7 +28,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2022_20353 extends StsExtraBusinessLogicHostTestBase {
+public class CVE_2022_20353 extends NonRootSecurityTestCase {
@AsbSecurityTest(cveBugId = 221041256)
@Test
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java
new file mode 100644
index 00000000000..067a011aa88
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20501.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20501 extends NonRootSecurityTestCase {
+ private ITestDevice mDevice;
+
+ /**
+ * b/246933359
+ * Vulnerable app : Telecom.apk
+ * Vulnerable module : com.android.server.telecom
+ * Is Play managed : No
+ */
+ @AsbSecurityTest(cveBugId = 246933359)
+ @Test
+ public void testPocCVE_2022_20501() {
+ try {
+ final String testPkg = "android.security.cts.CVE_2022_20501";
+ mDevice = getDevice();
+ installPackage("CVE-2022-20501.apk");
+
+ // Wake up the device
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP && wm dismiss-keyguard",
+ mDevice);
+
+ AdbUtils.runCommandLine(
+ "pm grant " + testPkg + " android.permission.SYSTEM_ALERT_WINDOW", mDevice);
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testOverlayButtonPresence");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+
+ @After
+ public void tearDown() {
+ try {
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", mDevice);
+ } catch (Exception ignored) {
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp
new file mode 100644
index 00000000000..14d6baf8331
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-0487",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml
new file mode 100644
index 00000000000..5c5934c342b
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_0487">
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <application>
+ <service android:name=".PocService" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_0487" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml
new file mode 100644
index 00000000000..de5f2533e30
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="pass">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml
new file mode 100644
index 00000000000..4d4098d003a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/res/values/strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="broadcastReceiverCalendar">CalendarProviderBroadcastReceiver</string>
+ <string name="calendarClsName">%1$s.CalendarDebugActivity</string>
+ <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="dumpsysActivity">dumpsys activity %1$s</string>
+ <string name="errorMessage">Device is vulnerable to b/174046397 hence any app with
+ "SYSTEM_ALERT_WINDOW" can overlay the CalendarDebugActivity screen</string>
+ <string name="messageKey">message</string>
+ <string name="overlayButtonText">OverlayButton</string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="resultKey">result</string>
+ <string name="resumedTrue">mResumed=true</string>
+ <string name="sharedPreferences">CVE_2021_0487_prefs</string>
+ <string name="vulActivityNotRunningError">The CalendarDebugActivity is not currently
+ running on the device</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java
new file mode 100644
index 00000000000..0a3e65db579
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/DeviceTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0487;
+
+import static android.provider.CalendarContract.ACTION_EVENT_REMINDER;
+import static android.provider.CalendarContract.CONTENT_URI;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+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.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final int LAUNCH_TIMEOUT_MS = 10000;
+ private String mVulnerablePkgName = "";
+ private Context mContext = getApplicationContext();
+ Resources mResources;
+
+ private void startOverlayService() {
+ Intent intent = new Intent(mContext, PocService.class);
+ assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startService(intent);
+ }
+
+ private void startVulnerableActivity() {
+ Intent intent = new Intent(ACTION_EVENT_REMINDER);
+ Intent vulnPkgNameIntent = new Intent();
+ intent.setData(CONTENT_URI);
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> ris = pm.queryBroadcastReceivers(intent, 0);
+ for (ResolveInfo ri : ris) {
+ if (ri.activityInfo.name
+ .contains(mContext.getString(R.string.broadcastReceiverCalendar))) {
+ mVulnerablePkgName = ri.activityInfo.packageName;
+ }
+ }
+ vulnPkgNameIntent.setClassName(mVulnerablePkgName,
+ mContext.getString(R.string.calendarClsName, mVulnerablePkgName));
+ vulnPkgNameIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(vulnPkgNameIntent);
+ }
+
+ @Test
+ public void testOverlayButtonPresence() {
+ try {
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+ /* Go to home screen */
+ device.pressHome();
+
+ /* Start the overlay service */
+ startOverlayService();
+ mResources = mContext.getResources();
+
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ mResources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(mResources.getString(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+
+ /* Wait for the overlay service to set some result in shared preferences */
+ assumeTrue(preferenceChanged.tryAcquire(LAUNCH_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ int result = sharedPrefs.getInt(mResources.getString(R.string.resultKey),
+ mResources.getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(mResources.getString(R.string.messageKey),
+ mResources.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != mResources.getInteger(R.integer.assumptionFailure));
+
+ /* Wait for the overlay window */
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)), LAUNCH_TIMEOUT_MS));
+
+ /* Start the vulnerable activity */
+ startVulnerableActivity();
+
+ /* Wait until the object of overlay window is gone */
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.pkg(mContext.getPackageName())), LAUNCH_TIMEOUT_MS);
+
+ /* Check if the currently running activity is the vulnerable activity */
+ String activityDump = device.executeShellCommand(
+ mContext.getString(R.string.dumpsysActivity, mVulnerablePkgName));
+ Pattern activityPattern = Pattern.compile(mContext.getString(R.string.resumedTrue),
+ Pattern.CASE_INSENSITIVE);
+ assumeTrue(mContext.getString(R.string.vulActivityNotRunningError),
+ activityPattern.matcher(activityDump).find());
+
+ /* Failing the test as fix is not present */
+ assertTrue(mContext.getString(R.string.errorMessage), overlayDisallowed);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java
new file mode 100644
index 00000000000..1a8cd0f2a3a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0487/src/android/security/cts/CVE_2021_0487/PocService.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_0487;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import androidx.annotation.IntegerRes;
+
+public class PocService extends Service {
+ private Button mButton;
+ private WindowManager mWindowManager;
+ private WindowManager.LayoutParams mLayoutParams;
+
+ int getInteger(@IntegerRes int resId) {
+ return getResources().getInteger(resId);
+ }
+
+ private static int getScreenWidth() {
+ return Resources.getSystem().getDisplayMetrics().widthPixels;
+ }
+
+ private static int getScreenHeight() {
+ return Resources.getSystem().getDisplayMetrics().heightPixels;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ try {
+ mWindowManager = getSystemService(WindowManager.class);
+ mLayoutParams = new WindowManager.LayoutParams();
+ mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ mLayoutParams.format = PixelFormat.OPAQUE;
+ mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ mLayoutParams.width = getScreenWidth();
+ mLayoutParams.height = getScreenHeight();
+ mLayoutParams.x = getScreenWidth() / 2;
+ mLayoutParams.y = getScreenHeight() / 2;
+ } catch (Exception e) {
+ sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ try {
+ showFloatingWindow();
+ sendTestResult(getInteger(R.integer.pass), "");
+ } catch (Exception e) {
+ sendTestResult(getInteger(R.integer.assumptionFailure), e.getMessage());
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public void onDestroy() {
+ try {
+ mWindowManager.removeView(mButton);
+ super.onDestroy();
+ } catch (Exception e) {
+ // ignore the exception
+ }
+ }
+
+ private void showFloatingWindow() {
+ mButton = new Button(this);
+ mButton.setText(getString(R.string.overlayButtonText));
+ mWindowManager.addView(mButton, mLayoutParams);
+ mButton.setTag(mButton.getVisibility());
+ }
+
+ private void sendTestResult(int result, String message) {
+ try {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ } catch (Exception e) {
+ // ignore the exception
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
index 167a849c948..3b1948552a4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-0921/src/android/security/cts/CVE_2021_0921/Trigger.java
@@ -11,8 +11,6 @@ import android.util.Log;
import java.io.File;
-import static org.junit.Assume.assumeNoException;
-
public class Trigger {
private static final String TAG = "TAG_2021_0921.Trigger";
private Context mContext;
@@ -26,8 +24,19 @@ public class Trigger {
return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
+ private static boolean isWear(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
+ private static boolean isTv(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION);
+ }
+
public void accountSettings() {
Log.d(TAG, "accountSettings() start");
+ String exitMessage = "accountSettings() end";
//replaces intent.setAction(Intent.ACTION_REBOOT) in original Poc
Intent arbitraryIntent = new Intent(mContext, TestActivity.class);
@@ -36,8 +45,19 @@ public class Trigger {
Authenticator.mIntent = arbitraryIntent;
Intent intent = new Intent();
- String pkg = isCar(mContext) ? "com.android.car.settings" : "com.android.settings";
- intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountSettings"));
+ String pkg = "com.android.settings";
+ if (isCar(mContext)) {
+ pkg = "com.android.car.settings";
+ intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountActivity"));
+ } else if (isTv(mContext)) {
+ pkg = "com.android.tv.settings";
+ intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountWithTypeActivity"));
+ } else if (isWear(mContext)) {
+ pkg = "com.google.android.clockwork.home";
+ intent.setComponent(new ComponentName(pkg, pkg + ".accounts.SetupAccountReceiver"));
+ } else {
+ intent.setComponent(new ComponentName(pkg, pkg + ".accounts.AddAccountSettings"));
+ }
intent.setAction(Intent.ACTION_RUN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String authTypes[] = {"android.security.cts"};
@@ -47,8 +67,9 @@ public class Trigger {
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- assumeNoException(e);
+ // activity does not exist on this device
+ exitMessage = "accountSettings() failure: activity does not exist on this device";
}
- Log.d(TAG, "accountSettings() end");
+ Log.d(TAG, exitMessage);
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp
new file mode 100644
index 00000000000..94988810449
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20501",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml
new file mode 100644
index 00000000000..5789b655741
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20501">
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <application>
+ <service android:name=".PocService"
+ android:enabled="true" />
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20501" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml
new file mode 100644
index 00000000000..2af8c0e3338
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?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="activityNotFoundMsg">The activity with intent %1$s was not found</string>
+ <string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="cmdDumpsysActivity">dumpsys activity %1$s</string>
+ <string name="dumpsysActivityException">Could not execute dumpsys activity command</string>
+ <string name="overlayButtonText">CVE_2022_20501_OverlayButton</string>
+ <string name="overlayErrorMessage">Device is vulnerable to b/246933359 hence any app with
+ "SYSTEM_ALERT_WINDOW permission can overlay the %1$s screen</string>
+ <string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
+ <string name="mResumedTrue">mResumed=true</string>
+ <string name="telUri">tel:6505551212</string>
+ <string name="telecomPkgDefault">com.android.server.telecom</string>
+ <string name="vulClsName">.settings.EnableAccountPreferenceActivity</string>
+ <string name="vulActivityNotRunningError">The %1$s is not currently running on the device
+ </string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java
new file mode 100644
index 00000000000..d6f51982d62
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/DeviceTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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_20501;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+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.UiAutomation;
+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.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private Context mContext;
+
+ private void startOverlayService() {
+ Intent intent = new Intent(mContext, PocService.class);
+ assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
+ mContext.startService(intent);
+ }
+
+ private String getTelecomPkgName() {
+ PackageManager pm = getInstrumentation().getTargetContext().getPackageManager();
+ UiAutomation ui = getInstrumentation().getUiAutomation();
+ String name = mContext.getString(R.string.telecomPkgDefault);
+ try {
+ ui.adoptShellPermissionIdentity(android.Manifest.permission.INTERACT_ACROSS_USERS);
+ Intent intent = new Intent(Intent.ACTION_CALL);
+ intent.setData(Uri.parse(mContext.getString(R.string.telUri)));
+ ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM);
+ name = info.activityInfo.packageName;
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ ui.dropShellPermissionIdentity();
+ }
+ return name;
+ }
+
+ @Test
+ public void testOverlayButtonPresence() {
+ try {
+ mContext = getApplicationContext();
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+
+ // Start the overlay service
+ startOverlayService();
+
+ // Wait for the overlay window
+ Pattern overlayTextPattern = Pattern.compile(
+ mContext.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ final long launchTimeoutMs = 20_000L;
+ assumeTrue(mContext.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs));
+
+ // Start the vulnerable activity
+ String pkg = getTelecomPkgName();
+ String cls = mContext.getString(R.string.vulClsName);
+ Intent intent = new Intent();
+ String vulActivity = pkg + cls;
+ intent.setClassName(pkg, vulActivity);
+ PackageManager pm = mContext.getPackageManager();
+ ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ assumeNotNull(mContext.getString(R.string.activityNotFoundMsg, intent), ri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+
+ // Wait until overlay window is gone
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.text(overlayTextPattern)), launchTimeoutMs);
+
+ // Check if the currently running activity is the vulnerable activity
+ String activityDump = device.executeShellCommand(
+ mContext.getString(R.string.cmdDumpsysActivity, vulActivity));
+
+ Pattern activityPattern = Pattern.compile(mContext.getString(R.string.mResumedTrue),
+ Pattern.CASE_INSENSITIVE);
+ assumeTrue(mContext.getString(R.string.vulActivityNotRunningError, vulActivity),
+ activityPattern.matcher(activityDump).find());
+
+ // Failing the test as overlay window is being allowed making code vulnerable
+ assertTrue(mContext.getString(R.string.overlayErrorMessage, vulActivity),
+ overlayDisallowed);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java
new file mode 100644
index 00000000000..8e1c5d380ca
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20501/src/android/security/cts/CVE_2022_20501/PocService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20501;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Button;
+
+public class PocService extends Service {
+ private Button mButton;
+ private WindowManager mWindowManager;
+
+ @Override
+ public void onCreate() {
+ try {
+ super.onCreate();
+ mWindowManager = getSystemService(WindowManager.class);
+ LayoutParams layoutParams = new LayoutParams();
+ layoutParams.type = LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags =
+ LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.format = PixelFormat.OPAQUE;
+ layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+ layoutParams.width = displayMetrics.widthPixels;
+ layoutParams.height = displayMetrics.heightPixels;
+ layoutParams.x = displayMetrics.widthPixels / 2;
+ layoutParams.y = displayMetrics.heightPixels / 2;
+
+ // Show the floating window
+ mButton = new Button(this);
+ mButton.setText(getString(R.string.overlayButtonText));
+ mWindowManager.addView(mButton, layoutParams);
+ } catch (Exception ignored) {
+ // In case of occurrence of an exception overlay won't appear on display which results in
+ // assumption failure in device test. Hence ignoring this exception here.
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ try {
+ mWindowManager.removeView(mButton);
+ } catch (Exception ignored) {
+ }
+ super.onDestroy();
+ }
+}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
index 42b9b5c9cd7..781be6b575f 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/UidAtomTests.java
@@ -34,7 +34,6 @@ import com.android.os.AtomsProto.AppBreadcrumbReported;
import com.android.os.AtomsProto.AppCrashOccurred;
import com.android.os.AtomsProto.AppUsageEventOccurred;
import com.android.os.AtomsProto.Atom;
-import com.android.os.AtomsProto.AttributionNode;
import com.android.os.AtomsProto.AudioStateChanged;
import com.android.os.AtomsProto.CameraStateChanged;
import com.android.os.AtomsProto.FlashlightStateChanged;
@@ -49,6 +48,7 @@ import com.android.os.AtomsProto.TestAtomReported;
import com.android.os.AtomsProto.UiEventReported;
import com.android.os.AtomsProto.VibratorStateChanged;
import com.android.os.AtomsProto.WakelockStateChanged;
+import com.android.os.AttributionNode;
import com.android.os.StatsLog.EventMetricData;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil;
diff --git a/tests/PhotoPicker/AndroidManifest.xml b/tests/PhotoPicker/AndroidManifest.xml
index e10bf5219ad..ca87690e795 100644
--- a/tests/PhotoPicker/AndroidManifest.xml
+++ b/tests/PhotoPicker/AndroidManifest.xml
@@ -19,7 +19,21 @@
package="android.photopicker.cts">
<application android:label="Photo Picker Device Tests">
<uses-library android:name="android.test.runner" />
- <activity android:name="android.photopicker.cts.GetResultActivity" />
+ <activity android:name="android.photopicker.cts.GetResultActivity"
+ android:exported="false"
+ android:enabled="true">
+ <intent-filter android:priority="999">
+ <action android:name="android.provider.action.PICK_IMAGES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="image/*" />
+ <data android:mimeType="video/*" />
+ </intent-filter>
+ <intent-filter android:priority="999">
+ <action android:name="android.provider.action.PICK_IMAGES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<provider android:name="android.photopicker.cts.cloudproviders.CloudProviderPrimary"
android:authorities="android.photopicker.cts.cloudproviders.cloud_primary"
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
index c7824bb2520..1746f4ecd14 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionGetContentOnlyTest.java
@@ -18,13 +18,12 @@ package android.photopicker.cts;
import static android.photopicker.cts.util.GetContentActivityAliasUtils.clearPackageData;
import static android.photopicker.cts.util.GetContentActivityAliasUtils.getDocumentsUiPackageName;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUriAndPath;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
import static android.photopicker.cts.util.PhotoPickerUiUtils.clickAndWait;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAndClickBrowse;
-
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertReadOnlyAccess;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -33,7 +32,7 @@ import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.photopicker.cts.util.GetContentActivityAliasUtils;
-import android.photopicker.cts.util.PhotoPickerUiUtils;
+import android.photopicker.cts.util.UiAssertionUtils;
import android.util.Pair;
import androidx.test.uiautomator.UiObject;
@@ -42,9 +41,7 @@ import androidx.test.uiautomator.UiScrollable;
import androidx.test.uiautomator.UiSelector;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
import java.util.ArrayList;
@@ -73,26 +70,19 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
if (mActivity != null) {
mActivity.finish();
}
- }
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- sDocumentsUiPackageName = getDocumentsUiPackageName();
- sGetContentTakeOverActivityAliasState = GetContentActivityAliasUtils.enableAndGetOldState();
+ GetContentActivityAliasUtils.restoreState(sGetContentTakeOverActivityAliasState);
}
@Before
public void setUp() throws Exception {
super.setUp();
+ sDocumentsUiPackageName = getDocumentsUiPackageName();
+ sGetContentTakeOverActivityAliasState = GetContentActivityAliasUtils.enableAndGetOldState();
clearPackageData(sDocumentsUiPackageName);
}
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- GetContentActivityAliasUtils.restoreState(sGetContentTakeOverActivityAliasState);
- }
-
@Test
public void testMimeTypeFilter() throws Exception {
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
@@ -100,7 +90,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("audio/*");
mActivity.startActivityForResult(intent, REQUEST_CODE);
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
// Should open documentsUi
assertThatShowsDocumentsUiButtons();
@@ -116,7 +106,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"video/*", "audio/*"});
mActivity.startActivityForResult(intent, REQUEST_CODE);
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
// Should open documentsUi
assertThatShowsDocumentsUiButtons();
@@ -140,7 +130,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
intent.setType("image/*");
mActivity.startActivityForResult(intent, REQUEST_CODE);
- findAndClickBrowse(mDevice);
+ findAndClickBrowse(sDevice);
findAndClickFilesInDocumentsUi(fileNameList);
@@ -166,7 +156,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
intent.setType("image/*");
mActivity.startActivityForResult(intent, REQUEST_CODE);
- findAndClickBrowse(mDevice);
+ findAndClickBrowse(sDevice);
findAndClickFilesInDocumentsUi(fileNameList);
@@ -185,7 +175,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
mActivity.startActivityForResult(Intent.createChooser(intent, TAG), REQUEST_CODE);
// Should open Picker
- assertThatShowsPickerUi();
+ UiAssertionUtils.assertThatShowsPickerUi();
}
@Test
@@ -207,7 +197,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
findAndClickMediaIcon();
// Should open Picker
- assertThatShowsPickerUi();
+ UiAssertionUtils.assertThatShowsPickerUi();
}
private void findAndClickMediaIcon() throws Exception {
@@ -219,30 +209,13 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
new UiObject(appList).waitForExists(SHORT_TIMEOUT)).isTrue();
String photoPickerAppName = "Media";
- UiObject mediaButton = mDevice.findObject(new UiSelector().text(photoPickerAppName));
+ UiObject mediaButton = sDevice.findObject(new UiSelector().text(photoPickerAppName));
assertWithMessage("Timed out waiting for " + photoPickerAppName + " app icon to appear")
.that(new UiScrollable(appList).scrollIntoView(mediaButton)).isTrue();
- mDevice.waitForIdle();
-
- clickAndWait(mDevice, mediaButton);
- }
-
- private void assertThatShowsPickerUi() {
- // Assert that Search bar for DocumentsUi shows
- // Add a short timeout wait for DocumentsUi to show
- assertThat(new UiObject(new UiSelector().resourceIdMatches(
- PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/bottom_sheet"))
- .waitForExists(SHORT_TIMEOUT)).isTrue();
-
- // Assert that "Recent files" header for DocumentsUi shows
- assertThat(new UiObject(new UiSelector().resourceIdMatches(
- PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/privacy_text"))
- .exists()).isTrue();
+ sDevice.waitForIdle();
- // Assert that Documents list UiObject for DocumentsUi shows
- assertThat(new UiObject(new UiSelector().text("Photos")).exists()).isTrue();
- assertThat(new UiObject(new UiSelector().text("Albums")).exists()).isTrue();
+ clickAndWait(sDevice, mediaButton);
}
private void assertThatShowsDocumentsUiButtons() {
@@ -268,7 +241,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
private void findAndClickSelect() throws Exception {
final UiObject selectButton = new UiObject(new UiSelector().resourceId(
sDocumentsUiPackageName + ":id/action_menu_select"));
- clickAndWait(mDevice, selectButton);
+ clickAndWait(sDevice, selectButton);
}
private void findAndClickFileInDocumentsUi(String fileName) throws Exception {
@@ -284,7 +257,7 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
// Enforce to set the list mode
// Because UiScrollable can't reach the real bottom (when WEB_LINKABLE_FILE item)
// in grid mode when screen landscape mode
- clickAndWait(mDevice, new UiObject(new UiSelector().resourceId(sDocumentsUiPackageName
+ clickAndWait(sDevice, new UiObject(new UiSelector().resourceId(sDocumentsUiPackageName
+ ":id/sub_menu_list")));
} catch (UiObjectNotFoundException ignored) {
// Do nothing, already be in list mode.
@@ -306,9 +279,9 @@ public class ActionGetContentOnlyTest extends PhotoPickerBaseTest {
}
}
- mDevice.swipe(/* startX= */ mDevice.getDisplayWidth() / 2,
- /* startY= */ mDevice.getDisplayHeight() / 2,
- /* endX= */ mDevice.getDisplayWidth() / 2,
+ sDevice.swipe(/* startX= */ sDevice.getDisplayWidth() / 2,
+ /* startY= */ sDevice.getDisplayHeight() / 2,
+ /* endX= */ sDevice.getDisplayWidth() / 2,
/* endY= */ 0,
/* steps= */ 40);
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
index 0f61dc74bbc..6cd0a7b8eed 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/ActionPickImagesOnlyTest.java
@@ -16,15 +16,15 @@
package android.photopicker.cts;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPersistedGrant;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUris;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
import static android.photopicker.cts.util.PhotoPickerUiUtils.clickAndWait;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPersistedGrant;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -36,7 +36,9 @@ import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
+import android.photopicker.cts.util.UiAssertionUtils;
import android.provider.MediaStore;
+import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiObject;
@@ -55,6 +57,7 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
+ private static final String TAG = "ActionPickImagesOnlyTest";
private List<Uri> mUriList = new ArrayList<>();
@After
@@ -70,6 +73,24 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
}
@Test
+ public void testPhotoPickerIntentDelegation() throws Exception {
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+
+ for (String mimeType: new String[] {
+ null,
+ "image/*",
+ "video/*"
+ }) {
+ Log.d(TAG, "Testing Photo Picker intent delegation with MimeType " + mimeType);
+ intent.setType(mimeType);
+
+ mActivity.startActivityForResult(Intent.createChooser(intent, TAG), REQUEST_CODE);
+
+ UiAssertionUtils.assertThatShowsPickerUi();
+ }
+ }
+
+ @Test
public void testMultiSelect_invalidParam() throws Exception {
final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, MediaStore.getPickImagesMaxLimit() + 1);
@@ -102,10 +123,10 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
assertThat(itemCount).isEqualTo(imageCount);
// Select maxCount + 1 item
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- UiObject snackbarTextView = mDevice.findObject(new UiSelector().text(
+ UiObject snackbarTextView = sDevice.findObject(new UiSelector().text(
"Select up to 2 items"));
assertWithMessage("Timed out while waiting for snackbar to appear").that(
snackbarTextView.waitForExists(SHORT_TIMEOUT)).isTrue();
@@ -113,7 +134,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
assertWithMessage("Timed out waiting for snackbar to disappear").that(
snackbarTextView.waitUntilGone(SHORT_TIMEOUT)).isTrue();
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
final int count = clipData.getItemCount();
@@ -132,7 +153,7 @@ public class ActionPickImagesOnlyTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isEqualTo(imageCount);
// Select 1 item
- clickAndWait(mDevice, itemList.get(0));
+ clickAndWait(sDevice, itemList.get(0));
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
index ceaf3b244e9..c89716f8d27 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/CloudPhotoPickerTest.java
@@ -20,11 +20,11 @@ import static android.os.SystemProperties.getBoolean;
import static android.photopicker.cts.PickerProviderMediaGenerator.MediaGenerator;
import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvider;
import static android.photopicker.cts.PickerProviderMediaGenerator.syncCloudProvider;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUris;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.provider.MediaStore.PickerMediaColumns;
import static com.google.common.truth.Truth.assertThat;
@@ -374,12 +374,12 @@ public class CloudPhotoPickerTest extends PhotoPickerBaseTest {
for (int i = 0; i < itemList.size(); i++) {
final UiObject item = itemList.get(i);
item.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
}
final UiObject addButton = findAddButton();
addButton.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
return mActivity.getResult().data.getClipData();
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
index 79d4b2bebb5..ca5a251cbb8 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
@@ -16,17 +16,13 @@
package android.photopicker.cts;
-import android.Manifest;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
-import android.provider.DeviceConfig;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
-import com.android.modules.utils.build.SdkLevel;
-
import org.junit.Before;
/**
@@ -35,32 +31,31 @@ import org.junit.Before;
*/
public class PhotoPickerBaseTest {
public static int REQUEST_CODE = 42;
+ private static final Instrumentation sInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+ protected static final UiDevice sDevice = UiDevice.getInstance(sInstrumentation);
protected GetResultActivity mActivity;
protected Context mContext;
- protected UiDevice mDevice;
@Before
public void setUp() throws Exception {
- final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
- mDevice = UiDevice.getInstance(inst);
-
final String setSyncDelayCommand =
"device_config put storage pickerdb.default_sync_delay_ms 0";
- mDevice.executeShellCommand(setSyncDelayCommand);
+ sDevice.executeShellCommand(setSyncDelayCommand);
- mContext = inst.getContext();
+ mContext = sInstrumentation.getContext();
final Intent intent = new Intent(mContext, GetResultActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// Wake up the device and dismiss the keyguard before the test starts
- mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- mDevice.executeShellCommand("wm dismiss-keyguard");
+ sDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ sDevice.executeShellCommand("wm dismiss-keyguard");
- mActivity = (GetResultActivity) inst.startActivitySync(intent);
+ mActivity = (GetResultActivity) sInstrumentation.startActivitySync(intent);
// Wait for the UI Thread to become idle.
- inst.waitForIdleSync();
+ sInstrumentation.waitForIdleSync();
mActivity.clearResult();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
}
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
index 48c1ea16b54..e06873ea867 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCrossProfileTest.java
@@ -16,14 +16,14 @@
package android.photopicker.cts;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUris;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findProfileButton;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -90,7 +90,7 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest {
// Click the profile button to change to personal profile
final UiObject profileButton = findProfileButton();
profileButton.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
final List<UiObject> itemList = findItemList(imageCount);
final int itemCount = itemList.size();
@@ -98,12 +98,12 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest {
for (int i = 0; i < itemCount; i++) {
final UiObject item = itemList.get(i);
item.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
}
final UiObject addButton = findAddButton();
addButton.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
final ClipData clipData = mActivity.getResult().data.getClipData();
final int count = clipData.getItemCount();
@@ -144,7 +144,7 @@ public class PhotoPickerCrossProfileTest extends PhotoPickerBaseTest {
// Click the profile button to change to work profile
final UiObject profileButton = findProfileButton();
profileButton.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
assertBlockedByAdminDialog(isInvokedFromWorkProfile);
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
new file mode 100644
index 00000000000..bfa0462dc18
--- /dev/null
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.photopicker.cts;
+
+import static android.os.SystemProperties.getBoolean;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.verifyActionBarExists;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActivityIsVisible;
+
+import android.content.Intent;
+import android.photopicker.cts.util.PhotoPickerUiUtils;
+import android.provider.MediaStore;
+
+import androidx.test.uiautomator.UiObject;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Photo Picker tests for settings page launched from the overflow menu in PhotoPickerActivity or
+ * the Settings app.
+ */
+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 final String SETTINGS_SYS_PROP =
+ "debug.photopicker.enable_settings_screen";
+
+ private static String sPreviouslyAllowedCloudProviders;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // Store current allowed cloud providers for reset at the end of tests.
+ sPreviouslyAllowedCloudProviders = sDevice.executeShellCommand(
+ String.format("device_config get %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
+ ALLOWED_CLOUD_PROVIDERS_KEY));
+
+ // 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));
+ sDevice.executeShellCommand(String.format("setprop %s true", SETTINGS_SYS_PROP));
+ Assume.assumeTrue(getBoolean(SETTINGS_SYS_PROP, false));
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ // 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));
+ }
+
+ // Disable Settings menu item in PhotoPickerActivity's overflow menu.
+ sDevice.executeShellCommand(String.format("setprop %s false", SETTINGS_SYS_PROP));
+ Assume.assumeFalse(getBoolean(SETTINGS_SYS_PROP, true));
+ }
+
+ @Test
+ public void testSettingsLaunchFromOverflowMenu() throws Exception {
+ // Launch PhotoPickerActivity.
+ final Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+ // Click on the Settings menu item in the overflow menu.
+ final UiObject settingsMenuItem = PhotoPickerUiUtils.findSettingsOverflowMenuItem(sDevice);
+ PhotoPickerUiUtils.clickAndWait(sDevice, settingsMenuItem);
+
+ // Verify PhotoPickerSettingsActivity is launched and visible.
+ verifySettingsActivityIsVisible(sDevice);
+ verifyActionBarExists(sDevice);
+ }
+}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 440e47288c2..11d99d1ed41 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -18,11 +18,6 @@ package android.photopicker.cts;
import static android.photopicker.cts.util.GetContentActivityAliasUtils.clearPackageData;
import static android.photopicker.cts.util.GetContentActivityAliasUtils.getDocumentsUiPackageName;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertContainsMimeType;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertMimeType;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPersistedGrant;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertPickerUriFormat;
-import static android.photopicker.cts.util.PhotoPickerAssertionsUtils.assertRedactedReadOnlyAccess;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createDNGVideosAndGetUris;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImagesAndGetUris;
import static android.photopicker.cts.util.PhotoPickerFilesUtils.createVideosAndGetUris;
@@ -34,6 +29,11 @@ import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findPreviewAddOrSelectButton;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertContainsMimeType;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertMimeType;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPersistedGrant;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertPickerUriFormat;
+import static android.photopicker.cts.util.ResultsAssertionsUtils.assertRedactedReadOnlyAccess;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -52,8 +52,7 @@ import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiSelector;
import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,17 +82,14 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
private static int sGetContentTakeOverActivityAliasState;
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
sGetContentTakeOverActivityAliasState = GetContentActivityAliasUtils.enableAndGetOldState();
clearPackageData(getDocumentsUiPackageName());
}
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- GetContentActivityAliasUtils.restoreState(sGetContentTakeOverActivityAliasState);
- }
-
@After
public void tearDown() throws Exception {
for (Uri uri : mUriList) {
@@ -104,6 +100,8 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
if (mActivity != null) {
mActivity.finish();
}
+
+ GetContentActivityAliasUtils.restoreState(sGetContentTakeOverActivityAliasState);
}
@Test
@@ -115,7 +113,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
launchPhotoPickerForIntent(intent);
final UiObject item = findItemList(itemCount).get(0);
- clickAndWait(mDevice, item);
+ clickAndWait(sDevice, item);
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
@@ -132,14 +130,14 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final Intent intent = new Intent(mAction);
launchPhotoPickerForIntent(intent);
- UiObject albumsTab = mDevice.findObject(new UiSelector().text(
+ UiObject albumsTab = sDevice.findObject(new UiSelector().text(
"Albums"));
- clickAndWait(mDevice, albumsTab);
+ clickAndWait(sDevice, albumsTab);
final UiObject album = findItemList(1).get(0);
- clickAndWait(mDevice, album);
+ clickAndWait(sDevice, album);
final UiObject item = findItemList(itemCount).get(0);
- clickAndWait(mDevice, item);
+ clickAndWait(sDevice, item);
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
@@ -156,11 +154,11 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
addMultipleSelectionFlag(intent);
launchPhotoPickerForIntent(intent);
- UiObject albumsTab = mDevice.findObject(new UiSelector().text(
+ UiObject albumsTab = sDevice.findObject(new UiSelector().text(
"Albums"));
- clickAndWait(mDevice, albumsTab);
+ clickAndWait(sDevice, albumsTab);
final UiObject album = findItemList(1).get(0);
- clickAndWait(mDevice, album);
+ clickAndWait(sDevice, album);
final List<UiObject> itemList = findItemList(videoCount);
final int itemCount = itemList.size();
@@ -168,10 +166,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
assertThat(itemCount).isEqualTo(videoCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findViewSelectedButton());
+ clickAndWait(sDevice, findViewSelectedButton());
// Wait for playback to start. This is needed in some devices where playback
// buffering -> ready state takes around 10s.
@@ -189,11 +187,11 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final UiObject item = findItemList(itemCount).get(0);
item.longClick();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
final UiObject addButton = findPreviewAddOrSelectButton();
assertThat(addButton.waitForExists(1000)).isTrue();
- clickAndWait(mDevice, addButton);
+ clickAndWait(sDevice, addButton);
final Uri uri = mActivity.getResult().data.getData();
assertPickerUriFormat(uri, mContext.getUserId());
@@ -212,10 +210,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isEqualTo(imageCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
final int count = clipData.getItemCount();
@@ -243,26 +241,26 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
assertThat(itemCount).isEqualTo(videoCount);
// Select one item from Photo grid
- clickAndWait(mDevice, itemList.get(0));
+ clickAndWait(sDevice, itemList.get(0));
// Preview the item
UiObject item = itemList.get(1);
item.longClick();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
final UiObject addOrSelectButton = findPreviewAddOrSelectButton();
assertWithMessage("Timed out waiting for AddOrSelectButton to appear")
.that(addOrSelectButton.waitForExists(1000)).isTrue();
// Select the item from Preview
- clickAndWait(mDevice, addOrSelectButton);
+ clickAndWait(sDevice, addOrSelectButton);
- mDevice.pressBack();
+ sDevice.pressBack();
// Select one more item from Photo grid
- clickAndWait(mDevice, itemList.get(2));
+ clickAndWait(sDevice, itemList.get(2));
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
// Verify that all 3 items are returned
final ClipData clipData = mActivity.getResult().data.getClipData();
@@ -289,10 +287,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isEqualTo(imageCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findViewSelectedButton());
+ clickAndWait(sDevice, findViewSelectedButton());
// Swipe left three times
swipeLeftAndWait();
@@ -300,10 +298,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
swipeLeftAndWait();
// Deselect one item
- clickAndWait(mDevice, findPreviewSelectedCheckButton());
+ clickAndWait(sDevice, findPreviewSelectedCheckButton());
// Return selected items
- clickAndWait(mDevice, findPreviewAddButton());
+ clickAndWait(sDevice, findPreviewAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
final int count = clipData.getItemCount();
@@ -350,20 +348,20 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
// Test 2: Click Mute Button
// Click to unmute the audio
- clickAndWait(mDevice, muteButton);
+ clickAndWait(sDevice, muteButton);
waitForBinderCallsToComplete();
// Check that mute button state is unmute, i.e., it shows `volume up` icon
assertMuteButtonState(muteButton, /* isMuted */ false);
// Click on the muteButton and check that mute button status is now 'mute'
- clickAndWait(mDevice, muteButton);
+ clickAndWait(sDevice, muteButton);
waitForBinderCallsToComplete();
assertMuteButtonState(muteButton, /* isMuted */ true);
// Click on the muteButton and check that mute button status is now unmute
- clickAndWait(mDevice, muteButton);
+ clickAndWait(sDevice, muteButton);
waitForBinderCallsToComplete();
@@ -371,8 +369,8 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
// Test 3: Next preview resumes mute state
// Go back and launch preview again
- mDevice.pressBack();
- clickAndWait(mDevice, findViewSelectedButton());
+ sDevice.pressBack();
+ clickAndWait(sDevice, findViewSelectedButton());
waitForBinderCallsToComplete();
@@ -408,7 +406,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
// Test 2: Swipe resumes mute state, with state of mute button 'volume up' / 'unmute'
// Click muteButton again to check the next video resumes the previous video's mute state
- clickAndWait(mDevice, muteButton);
+ clickAndWait(sDevice, muteButton);
waitForBinderCallsToComplete();
@@ -462,12 +460,12 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final UiObject muteButton = findMuteButton();
// unmute the audio of video preview
- clickAndWait(mDevice, muteButton);
+ clickAndWait(sDevice, muteButton);
// Remote video preview involves binder calls
// Wait for Binder calls to complete and device to be idle
MediaStore.waitForIdle(mContext.getContentResolver());
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
assertMuteButtonState(muteButton, /* isMuted */ false);
@@ -512,7 +510,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final UiObject playerView = findPlayerView();
// Click on StyledPlayerView to make the video controls visible
- clickAndWait(mDevice, playerView);
+ clickAndWait(sDevice, playerView);
assertPlayerControlsVisible(playPauseButton, muteButton);
// Wait for 1s and check that controls are still visible
@@ -521,7 +519,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
// Click on StyledPlayerView and check that controls are no longer visible. Don't click in
// the center, clicking in the center may pause the video.
playerView.clickBottomRight();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
assertPlayerControlsHidden(playPauseButton, muteButton);
// Swipe left and check that controls are not visible
@@ -529,7 +527,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
assertPlayerControlsHidden(playPauseButton, muteButton);
// Click on the StyledPlayerView and check that controls appear
- clickAndWait(mDevice, playerView);
+ clickAndWait(sDevice, playerView);
assertPlayerControlsVisible(playPauseButton, muteButton);
// Swipe left to check that controls are now visible on swipe
@@ -562,10 +560,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isAtLeast(videoCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
final int count = clipData.getItemCount();
@@ -608,10 +606,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isAtLeast(totalCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
assertWithMessage("Expected number of items returned to be: " + itemCount)
@@ -645,10 +643,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
final int itemCount = itemList.size();
assertThat(itemCount).isAtLeast(videoCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findAddButton());
+ clickAndWait(sDevice, findAddButton());
final ClipData clipData = mActivity.getResult().data.getClipData();
assertWithMessage("Expected number of items returned to be: " + itemCount)
@@ -681,16 +679,16 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
assertPlayerControlsAutoHide(playPauseButton, muteButton);
// Click on StyledPlayerView to make the video controls visible
- clickAndWait(mDevice, findPlayerView());
+ clickAndWait(sDevice, findPlayerView());
// PlayPause button is now pause button, click the button to pause the video.
- clickAndWait(mDevice, playPauseButton);
+ clickAndWait(sDevice, playPauseButton);
// Wait for 1s and check that play button is not auto hidden
assertPlayerControlsDontAutoHide(playPauseButton, muteButton);
// PlayPause button is now play button, click the button to play the video.
- clickAndWait(mDevice, playPauseButton);
+ clickAndWait(sDevice, playPauseButton);
// Check that pause button auto-hides in 1s.
assertPlayerControlsAutoHide(playPauseButton, muteButton);
}
@@ -709,10 +707,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
assertThat(itemCount).isEqualTo(videoCount);
for (int i = 0; i < itemCount; i++) {
- clickAndWait(mDevice, itemList.get(i));
+ clickAndWait(sDevice, itemList.get(i));
}
- clickAndWait(mDevice, findViewSelectedButton());
+ clickAndWait(sDevice, findViewSelectedButton());
// Wait for playback to start. This is needed in some devices where playback
// buffering -> ready state takes around 10s.
@@ -725,7 +723,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
private void waitForBinderCallsToComplete() {
// Wait for Binder calls to complete and device to be idle
MediaStore.waitForIdle(mContext.getContentResolver());
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
}
private void setUpAndAssertStickyPlayerControls(UiObject playerView, UiObject playPauseButton,
@@ -735,7 +733,7 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
// Wait for 1s or Play/Pause button to hide
playPauseButton.waitUntilGone(1000);
// Click on StyledPlayerView to make the video controls visible
- clickAndWait(mDevice, playerView);
+ clickAndWait(sDevice, playerView);
assertPlayerControlsVisible(playPauseButton, muteButton);
}
@@ -811,10 +809,10 @@ public class PhotoPickerTest extends PhotoPickerBaseTest {
}
private void swipeLeftAndWait() {
- final int width = mDevice.getDisplayWidth();
- final int height = mDevice.getDisplayHeight();
- mDevice.swipe(15 * width / 20, height / 2, width / 20, height / 2, 10);
- mDevice.waitForIdle();
+ final int width = sDevice.getDisplayWidth();
+ final int height = sDevice.getDisplayHeight();
+ sDevice.swipe(15 * width / 20, height / 2, width / 20, height / 2, 10);
+ sDevice.waitForIdle();
}
private static List<String> getTestParameters() {
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
index db60d7ddd8c..20b22c56acf 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/RemoteVideoPreviewTest.java
@@ -92,7 +92,7 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
Assume.assumeTrue(getBoolean("sys.photopicker.pickerdb.enabled", true));
- mDevice.executeShellCommand("setprop sys.photopicker.remote_preview true");
+ sDevice.executeShellCommand("setprop sys.photopicker.remote_preview true");
Assume.assumeTrue(getBoolean("sys.photopicker.remote_preview", true));
mCloudPrimaryMediaGenerator = PickerProviderMediaGenerator.getMediaGenerator(
@@ -134,7 +134,7 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
// TODO(b/215187981): Add test for onMediaPause()
// Exit preview mode
- mDevice.pressBack();
+ sDevice.pressBack();
// Remote Preview calls onSurfaceDestroyed, check if the id is the same (as the
// CloudMediaProvider is only rendering to one surface id)
@@ -354,7 +354,7 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
+ "retriable error")
.that(findPreviewErrorAlertDialogRetryButton().waitForExists(SHORT_TIMEOUT))
.isTrue();
- clickAndWait(mDevice, findPreviewErrorAlertDialogRetryButton());
+ clickAndWait(sDevice, findPreviewErrorAlertDialogRetryButton());
mAssertInOrder.verify(mSurfaceControllerListener).onMediaPlay(eq(surfaceId));
}
@@ -402,12 +402,12 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
for (final UiObject item : itemList) {
item.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
}
final UiObject viewSelectedButton = findViewSelectedButton();
viewSelectedButton.click();
- mDevice.waitForIdle();
+ sDevice.waitForIdle();
// Wait for CloudMediaProvider binder calls to finish.
MediaStore.waitForIdle(mContext.getContentResolver());
@@ -419,20 +419,20 @@ public class RemoteVideoPreviewTest extends PhotoPickerBaseTest {
}
private void swipeLeftAndWait() throws Exception {
- final int width = mDevice.getDisplayWidth();
- final int height = mDevice.getDisplayHeight();
- mDevice.swipe(width / 2, height / 2, width / 4, height / 2, 10);
- mDevice.waitForIdle();
+ final int width = sDevice.getDisplayWidth();
+ final int height = sDevice.getDisplayHeight();
+ sDevice.swipe(width / 2, height / 2, width / 4, height / 2, 10);
+ sDevice.waitForIdle();
// Wait for CloudMediaProvider binder calls to finish.
MediaStore.waitForIdle(mContext.getContentResolver());
}
private void swipeRightAndWait() throws Exception {
- final int width = mDevice.getDisplayWidth();
- final int height = mDevice.getDisplayHeight();
- mDevice.swipe(width / 4, height / 2, width / 2, height / 2, 10);
- mDevice.waitForIdle();
+ final int width = sDevice.getDisplayWidth();
+ final int height = sDevice.getDisplayHeight();
+ sDevice.swipe(width / 4, height / 2, width / 2, height / 2, 10);
+ sDevice.waitForIdle();
// Wait for CloudMediaProvider binder calls to finish.
MediaStore.waitForIdle(mContext.getContentResolver());
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
index 8f58f3e3261..5cdb5927ea3 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
@@ -95,18 +95,49 @@ public class PhotoPickerUiUtils {
}
public static void findAndClickBrowse(UiDevice uiDevice) throws Exception {
- assertWithMessage("Timed out waiting for overflow menu to appear")
- .that(new UiObject(new UiSelector().description("More options"))
- .waitForExists(SHORT_TIMEOUT))
- .isTrue();
-
- final UiObject overflowMenu = new UiObject(new UiSelector().description("More options"));
+ final UiObject overflowMenu = getOverflowMenuObject(uiDevice);
clickAndWait(uiDevice, overflowMenu);
final UiObject browseButton = new UiObject(new UiSelector().textContains("Browse"));
clickAndWait(uiDevice, browseButton);
}
+ public static UiObject findSettingsOverflowMenuItem(UiDevice uiDevice) throws Exception {
+ final UiObject overflowMenu = getOverflowMenuObject(uiDevice);
+ clickAndWait(uiDevice, overflowMenu);
+ return new UiObject(new UiSelector().textContains("Settings"));
+ }
+
+ public static UiObject getOverflowMenuObject(UiDevice uiDevice) {
+ // Wait for overflow menu to appear.
+ verifyOverflowMenuExists(uiDevice);
+ return new UiObject(new UiSelector().description("More options"));
+ }
+
+ public static void verifyActionBarExists(UiDevice uiDevice) {
+ assertWithMessage("Timed out waiting for action bar to appear")
+ .that(new UiObject(new UiSelector()
+ .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/action_bar"))
+ .waitForExists(TIMEOUT))
+ .isTrue();
+ }
+
+ private static void verifyOverflowMenuExists(UiDevice uiDevice) {
+ assertWithMessage("Timed out waiting for overflow menu to appear")
+ .that(new UiObject(new UiSelector().description("More options"))
+ .waitForExists(TIMEOUT))
+ .isTrue();
+ }
+
+ public static void verifySettingsActivityIsVisible(UiDevice uiDevice) {
+ // 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()
+ .resourceIdMatches(REGEX_PACKAGE_NAME + ":id/settings_activity_root"))
+ .waitForExists(TIMEOUT))
+ .isTrue();
+ }
+
public static void clickAndWait(UiDevice uiDevice, UiObject uiObject) throws Exception {
uiObject.click();
uiDevice.waitForIdle();
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java
index 6d86cee66b9..e08dd2a1e2e 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerAssertionsUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/ResultsAssertionsUtils.java
@@ -46,9 +46,9 @@ import java.util.Arrays;
import java.util.List;
/**
- * Photo Picker Utility methods for test assertions.
+ * Photo Picker Utility methods for PhotoPicker result assertions.
*/
-public class PhotoPickerAssertionsUtils {
+public class ResultsAssertionsUtils {
private static final String TAG = "PhotoPickerTestAssertions";
public static void assertPickerUriFormat(Uri uri, int expectedUserId) {
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/UiAssertionUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/UiAssertionUtils.java
new file mode 100644
index 00000000000..7caeb6ad833
--- /dev/null
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/UiAssertionUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.photopicker.cts.util;
+
+import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.uiautomator.UiObject;
+import androidx.test.uiautomator.UiSelector;
+
+/**
+ * Photo Picker Utility methods for PhotoPicker UI assertions.
+ */
+public class UiAssertionUtils {
+ /**
+ * Verifies PhotoPicker UI is shown.
+ */
+ public static void assertThatShowsPickerUi() {
+ // Assert that Bottom Sheet is shown
+ // Add a short timeout wait for PhotoPicker to show
+ assertThat(new UiObject(new UiSelector().resourceIdMatches(
+ PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/bottom_sheet"))
+ .waitForExists(SHORT_TIMEOUT)).isTrue();
+
+ // Assert that privacy text is shown
+ assertThat(new UiObject(new UiSelector().resourceIdMatches(
+ PhotoPickerUiUtils.REGEX_PACKAGE_NAME + ":id/privacy_text"))
+ .exists()).isTrue();
+
+ // Assert that "Photos" and "Albums" headers are shown.
+ assertThat(new UiObject(new UiSelector().text("Photos")).exists()).isTrue();
+ assertThat(new UiObject(new UiSelector().text("Albums")).exists()).isTrue();
+ }
+}
diff --git a/tests/accessibility/Android.bp b/tests/accessibility/Android.bp
index 91ce26b6898..03c7d1b85a7 100644
--- a/tests/accessibility/Android.bp
+++ b/tests/accessibility/Android.bp
@@ -21,6 +21,7 @@ java_library_static {
sdk_version: "test_current",
static_libs: [
"compatibility-device-util-axt",
+ "sts-device-util",
],
srcs: ["common/src/**/*.java"],
}
@@ -39,6 +40,7 @@ android_test {
test_suites: [
"cts",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
}
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index bf3b1a82567..056ca59ec8a 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -60,6 +60,17 @@
android:resource="@xml/speaking_and_vibrating_accessibilityservice"/>
</service>
+ <service android:name=".NoFeedbackAccessibilityService"
+ android:label="@string/title_no_feedback_accessibility_service"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/no_feedback_accessibilityservice"/>
+ </service>
+
<service android:name=".AccessibilityButtonService"
android:label="@string/title_accessibility_button_service"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index 37d30516bc0..871d5f9955a 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -26,6 +26,9 @@
<!-- String title for the vibrating accessibility service -->
<string name="title_speaking_and_vibrating_accessibility_service">Speaking and Vibrating Accessibility Service</string>
+ <!-- String title for the no-feedback accessibility service -->
+ <string name="title_no_feedback_accessibility_service">No-Feedback Accessibility Service</string>
+
<!-- String title for the accessibility button service -->
<string name="title_accessibility_button_service">Accessibility Button Service</string>
diff --git a/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
new file mode 100644
index 00000000000..168e5845031
--- /dev/null
+++ b/tests/accessibility/res/xml/no_feedback_accessibilityservice.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 0f5afd15ef6..27c3aac53cf 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -34,6 +34,7 @@ import android.app.UiAutomation;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Handler;
+import android.platform.test.annotations.AsbSecurityTest;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -44,6 +45,8 @@ import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SettingsStateChangerRule;
import com.android.compatibility.common.util.SystemUtil;
@@ -63,7 +66,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Class for testing {@link AccessibilityManager}.
*/
@RunWith(AndroidJUnit4.class)
-public class AccessibilityManagerTest {
+public class AccessibilityManagerTest extends StsExtraBusinessLogicTestCase {
private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
new AccessibilityDumpOnFailureRule();
@@ -81,6 +84,11 @@ public class AccessibilityManagerTest {
new InstrumentedAccessibilityServiceTestRule<>(
SpeakingAndVibratingAccessibilityService.class, false);
+ private InstrumentedAccessibilityServiceTestRule<NoFeedbackAccessibilityService>
+ mNoFeedbackAccessibilityServiceRule =
+ new InstrumentedAccessibilityServiceTestRule<>(
+ NoFeedbackAccessibilityService.class, false);
+
private static final Instrumentation sInstrumentation =
InstrumentationRegistry.getInstrumentation();
@@ -93,6 +101,9 @@ public class AccessibilityManagerTest {
private static final String MULTIPLE_FEEDBACK_TYPES_ACCESSIBILITY_SERVICE_NAME =
"android.view.accessibility.cts.SpeakingAndVibratingAccessibilityService";
+ private static final String NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME =
+ "android.view.accessibility.cts.NoFeedbackAccessibilityService";
+
public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_non_interactive_ui_timeout_ms";
@@ -112,6 +123,7 @@ public class AccessibilityManagerTest {
// SettingsStateChangerRule will suppress accessibility services, so it should be
// executed before enabling a11y services and after disabling a11y services.
.outerRule(mAudioDescriptionSetterRule)
+ .around(mNoFeedbackAccessibilityServiceRule)
.around(mSpeakingAndVibratingAccessibilityServiceRule)
.around(mVibratingAccessibilityServiceRule)
.around(mSpeakingAccessibilityServiceRule)
@@ -241,6 +253,26 @@ public class AccessibilityManagerTest {
assertTrue("The vibrating service should be enabled.", vibratingServiceEnabled);
}
+ @AsbSecurityTest(cveBugId = {243849844})
+ @Test
+ public void testGetEnabledAccessibilityServiceList_NoFeedback() {
+ mNoFeedbackAccessibilityServiceRule.enableService();
+ List<AccessibilityServiceInfo> enabledServices =
+ mAccessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+ boolean noFeedbackServiceEnabled = false;
+ final int serviceCount = enabledServices.size();
+ for (int i = 0; i < serviceCount; i++) {
+ AccessibilityServiceInfo enabledService = enabledServices.get(i);
+ ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
+ if (mTargetContext.getPackageName().equals(serviceInfo.packageName)
+ && NO_FEEDBACK_ACCESSIBILITY_SERVICE_NAME.equals(serviceInfo.name)) {
+ noFeedbackServiceEnabled = true;
+ }
+ }
+ assertTrue("The no-feedback service should be enabled.", noFeedbackServiceEnabled);
+ }
+
@Test
public void testGetEnabledAccessibilityServiceListForType() throws Exception {
mSpeakingAccessibilityServiceRule.enableService();
diff --git a/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
new file mode 100644
index 00000000000..0c79ae41515
--- /dev/null
+++ b/tests/accessibility/src/android/view/accessibility/cts/NoFeedbackAccessibilityService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility.cts;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+import android.content.ComponentName;
+
+/**
+ * Stub accessibility service that reports itself as providing no feedback.
+ */
+public class NoFeedbackAccessibilityService extends InstrumentedAccessibilityService {
+ public static final ComponentName COMPONENT_NAME = new ComponentName(
+ "android.view.accessibility.cts",
+ "android.view.accessibility.cts.NoFeedbackAccessibilityService");
+}
diff --git a/tests/accessibilityservice/Android.bp b/tests/accessibilityservice/Android.bp
index 876da5a62cf..9e891ee86b5 100644
--- a/tests/accessibilityservice/Android.bp
+++ b/tests/accessibilityservice/Android.bp
@@ -27,6 +27,7 @@ android_test {
"platform-test-annotations",
"CtsAccessibilityCommon",
"CtsInputMethodServiceCommon",
+ "sts-device-util",
],
libs: [
"android.test.runner",
@@ -37,10 +38,12 @@ android_test {
test_suites: [
"cts",
"general-tests",
+ "sts",
],
sdk_version: "test_current",
per_testcase_directory: true,
data: [
":CtsInputMethod1",
+ ":CtsAccessibilityMultipleServicesApp",
":CtsAccessibilityWidgetProvider"],
}
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 3bde0fd1dd1..ad7994e4fb5 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -27,6 +27,8 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
+ <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
+
<application android:theme="@android:style/Theme.Holo.NoActionBar"
android:requestLegacyExternalStorage="true">
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index 48aea2c3a0f..8096d296893 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -24,6 +24,11 @@
<option name="run-command" value="cmd accessibility set-bind-instant-service-allowed true" />
<option name="teardown-command" value="cmd accessibility set-bind-instant-service-allowed false" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="CtsAccessibilityMultipleServicesApp.apk"
+ value="/data/local/tmp/cts/content/CtsAccessibilityMultipleServicesApp.apk" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAccessibilityServiceTestCases.apk" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 5f9733c61c8..52fb4c37e7f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -17,7 +17,9 @@
package android.accessibilityservice.cts;
import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.accessibility.cts.common.InstrumentedAccessibilityService.TIMEOUT_SERVICE_ENABLE;
import static android.accessibility.cts.common.InstrumentedAccessibilityService.enableService;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventType;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventTypeWithAction;
import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterForEventTypeWithResource;
@@ -76,7 +78,9 @@ import android.graphics.Region;
import android.os.Process;
import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.AsbSecurityTest;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.TextUtils;
import android.util.Log;
@@ -99,6 +103,9 @@ import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.CtsMouseUtil;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
import org.junit.After;
import org.junit.AfterClass;
@@ -120,7 +127,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* are generated and their correct dispatch verified.
*/
@RunWith(AndroidJUnit4.class)
-public class AccessibilityEndToEndTest {
+public class AccessibilityEndToEndTest extends StsExtraBusinessLogicTestCase {
private static final String LOG_TAG = "AccessibilityEndToEndTest";
@@ -1013,6 +1020,71 @@ public class AccessibilityEndToEndTest {
}
}
+ @AsbSecurityTest(cveBugId = {243378132})
+ @Test
+ public void testUninstallPackage_DisablesMultipleServices() throws Exception {
+ final String apkPath =
+ "/data/local/tmp/cts/content/CtsAccessibilityMultipleServicesApp.apk";
+ final String packageName = "foo.bar.multipleservices";
+ final ComponentName service1 = ComponentName.createRelative(packageName, ".StubService1");
+ final ComponentName service2 = ComponentName.createRelative(packageName, ".StubService2");
+ // Match AccessibilityManagerService#COMPONENT_NAME_SEPARATOR
+ final String componentNameSeparator = ":";
+
+ final String originalEnabledServicesSetting = getEnabledServicesSetting();
+
+ try {
+ // Install the apk in this test method, instead of as part of the target preparer, to
+ // allow repeated --iterations of the test.
+ com.google.common.truth.Truth.assertThat(
+ ShellUtils.runShellCommand("pm install " + apkPath)).startsWith("Success");
+
+ // Enable the two services and wait until AccessibilityManager reports them as enabled.
+ final String servicesToEnable = getEnabledServicesSetting() + componentNameSeparator
+ + service1.flattenToShortString() + componentNameSeparator
+ + service2.flattenToShortString();
+ ShellCommandBuilder.create(sInstrumentation)
+ .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ servicesToEnable)
+ .putSecureSetting(Settings.Secure.ACCESSIBILITY_ENABLED, "1")
+ .run();
+ TestUtils.waitUntil("Failed to enable 2 services from package " + packageName,
+ (int) TIMEOUT_SERVICE_ENABLE / 1000,
+ () -> getEnabledServices().stream().filter(
+ info -> info.getId().startsWith(packageName)).count() == 2);
+
+ // Uninstall the package that contains the services.
+ com.google.common.truth.Truth.assertThat(
+ ShellUtils.runShellCommand("pm uninstall " + packageName)).startsWith(
+ "Success");
+
+ // Ensure the uninstall removed the services from the secure setting.
+ TestUtils.waitUntil(
+ "Failed to disable services after uninstalling package " + packageName,
+ (int) TIMEOUT_SERVICE_ENABLE / 1000,
+ () -> !getEnabledServicesSetting().contains(packageName));
+ } finally {
+ ShellCommandBuilder.create(sInstrumentation)
+ .putSecureSetting(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ originalEnabledServicesSetting)
+ .run();
+ ShellUtils.runShellCommand("pm uninstall " + packageName);
+ }
+ }
+
+ private List<AccessibilityServiceInfo> getEnabledServices() {
+ return ((AccessibilityManager) sInstrumentation.getContext().getSystemService(
+ Context.ACCESSIBILITY_SERVICE)).getEnabledAccessibilityServiceList(
+ FEEDBACK_ALL_MASK);
+ }
+
+ private String getEnabledServicesSetting() {
+ final String result = Settings.Secure.getString(
+ sInstrumentation.getContext().getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ return result != null ? result : "";
+ }
+
private static void assertPackageName(AccessibilityNodeInfo node, String packageName) {
if (node == null) {
return;
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp b/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp
new file mode 100644
index 00000000000..d8fdbceba09
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/Android.bp
@@ -0,0 +1,24 @@
+// 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: "CtsAccessibilityMultipleServicesApp",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "test_current",
+}
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml b/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml
new file mode 100644
index 00000000000..649478eda56
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar.multipleservices"
+ android:targetSandboxVersion="2">
+ <application>
+ <service android:name="foo.bar.multipleservices.StubService1"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/stub_service"/>
+ </service>
+ <service android:name="foo.bar.multipleservices.StubService2"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/stub_service"/>
+ </service>
+ </application>
+</manifest>
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml b/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml
new file mode 100644
index 00000000000..0cbd1399ec9
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/res/xml/stub_service.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java
new file mode 100644
index 00000000000..022f6e19ee8
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService1.java
@@ -0,0 +1,29 @@
+/*
+ * 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 foo.bar.multipleservices;
+
+import android.accessibilityservice.AccessibilityService;
+import android.view.accessibility.AccessibilityEvent;
+
+/** A stub accessibility service for testing package uninstall. */
+public class StubService1 extends AccessibilityService {
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {}
+
+ @Override
+ public void onInterrupt() {}
+}
diff --git a/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java
new file mode 100644
index 00000000000..28353c255c0
--- /dev/null
+++ b/tests/accessibilityservice/test-apps/MultipleServicesApp/src/foo/bar/multipleservices/StubService2.java
@@ -0,0 +1,29 @@
+/*
+ * 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 foo.bar.multipleservices;
+
+import android.accessibilityservice.AccessibilityService;
+import android.view.accessibility.AccessibilityEvent;
+
+/** A stub accessibility service for testing package uninstall. */
+public class StubService2 extends AccessibilityService {
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {}
+
+ @Override
+ public void onInterrupt() {}
+}
diff --git a/tests/backup/AndroidTest.xml b/tests/backup/AndroidTest.xml
index 0e8466247c9..d4498707eb3 100644
--- a/tests/backup/AndroidTest.xml
+++ b/tests/backup/AndroidTest.xml
@@ -20,6 +20,7 @@
<!-- Backup of instant apps is not supported. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.permission.apex" />
<!-- Run module in system user because backup tests are not fully supported in secondary user.
For devices running on secondary user, such as automotive devices, these tests will fail.
When backup tests are fully functional for secondary users:
diff --git a/tests/backup/TEST_MAPPING b/tests/backup/TEST_MAPPING
index 4e5beb081b0..1e1dcdb211c 100644
--- a/tests/backup/TEST_MAPPING
+++ b/tests/backup/TEST_MAPPING
@@ -3,5 +3,15 @@
{
"name": "CtsBackupTestCases"
}
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsBackupTestCases[com.google.android.permission.apex]",
+ "options": [
+ {
+ "include-filter": "android.backup.cts.PermissionTest"
+ }
+ ]
+ }
]
}
diff --git a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
index 2baa2f1d3be..c448a7606a2 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/GeocoderTest.java
@@ -16,12 +16,7 @@
package android.location.cts.fine;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.mock;
@@ -29,8 +24,6 @@ import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.ResolveInfoFlags;
import android.location.Geocoder;
import android.location.Geocoder.GeocodeListener;
import android.platform.test.annotations.AppModeFull;
@@ -64,17 +57,6 @@ public class GeocoderTest {
mGeocoder = new Geocoder(mContext, Locale.US);
}
- @Test
- public void testIsPresent() {
- if (mContext.getPackageManager().queryIntentServices(
- new Intent("com.android.location.service.GeocodeProvider"), ResolveInfoFlags.of(
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE)).isEmpty()) {
- assertFalse(Geocoder.isPresent());
- } else {
- assertTrue(Geocoder.isPresent());
- }
- }
-
@ApiTest(apis = "android.location.Geocoder#getFromLocation")
@AppModeFull(reason = "b/238831704 - Test cases don't apply for Instant apps")
@Test
diff --git a/tests/media/AndroidTest.xml b/tests/media/AndroidTest.xml
index 588ddf8dc2a..ef5dbeb6897 100644
--- a/tests/media/AndroidTest.xml
+++ b/tests/media/AndroidTest.xml
@@ -19,6 +19,14 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-test-harness" value="false" />
+ <option name="screen-always-on" value="on" />
+ <option name="screen-adaptive-brightness" value="off" />
+ <option name="disable-audio" value="false"/>
+ <option name="screen-saver" value="off"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="CtsMediaV2TestCases" />
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 9d1d839c47d..61772986c3b 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -594,6 +594,9 @@ abstract class CodecTestBase {
public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
public static final boolean IS_AT_LEAST_T =
ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
+ //TODO(b/248315681) Remove codenameEquals() check once devices return correct version for U
+ public static final boolean IS_AT_LEAST_U = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU)
+ || ApiLevelUtil.codenameEquals("UpsideDownCake");
public static final boolean FIRST_SDK_IS_AT_LEAST_T =
ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU);
public static final boolean VNDK_IS_AT_LEAST_T =
diff --git a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
index 518ff8610a8..9039d38b2cc 100644
--- a/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/DecodeGlAccuracyTest.java
@@ -351,7 +351,7 @@ public class DecodeGlAccuracyTest extends CodecDecoderTestBase {
// limit the test to devices launching with T
assumeTrue("Skipping color range " + mRange + " and color standard " + mStandard +
" for devices upgrading to T",
- FIRST_SDK_IS_AT_LEAST_T);
+ FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T);
// TODO (b/219748700): Android software codecs work only with 601LR. Skip for now.
assumeTrue("Skipping " + mCompName + " for color range " + mRange
diff --git a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
index ebed139fc53..6bcd5c77195 100644
--- a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
@@ -27,6 +27,8 @@ import android.view.Surface;
import androidx.test.filters.LargeTest;
+import com.android.compatibility.common.util.MediaUtils;
+
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
@@ -138,6 +140,11 @@ public class EncodeDecodeAccuracyTest extends CodecDecoderTestBase {
@Before
public void setUp() throws IOException {
+ // Few cuttlefish specific color conversion issues were fixed after Android T.
+ if (MediaUtils.onCuttlefish()) {
+ assumeTrue("Color conversion related tests are not valid on cuttlefish releases "
+ + "through android T", IS_AT_LEAST_U);
+ }
if (mUseHighBitDepth) {
assumeTrue("Codec doesn't support ABGR2101010",
hasSupportForColorFormat(mCompName, mMime, COLOR_Format32bitABGR2101010));
diff --git a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
index 72e4765a0db..a2563a3e544 100644
--- a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
@@ -29,6 +29,7 @@ import android.view.Surface;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.MediaUtils;
import org.junit.Assume;
import org.junit.Test;
@@ -265,7 +266,12 @@ public class EncoderColorAspectsTest extends CodecEncoderTestBase {
Assume.assumeTrue("Test introduced with Android 11", sIsAtLeastR);
if (mSurfaceMode) {
Assume.assumeTrue("Surface mode tests are limited to devices launching with Android T",
- FIRST_SDK_IS_AT_LEAST_T);
+ FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T);
+ // Few cuttlefish specific color conversion issues were fixed after Android T.
+ if (MediaUtils.onCuttlefish()) {
+ Assume.assumeTrue("Color conversion related tests are not valid on cuttlefish "
+ + "releases through android T", IS_AT_LEAST_U);
+ }
}
if (mUseHighBitDepth) {
diff --git a/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java b/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
index a0467a2f692..c82e0392fad 100644
--- a/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
+++ b/tests/ondevicepersonalization/src/android/ondevicepersonalization/cts/OnDevicePersonalizationServiceTest.java
@@ -16,14 +16,6 @@
package android.ondevicepersonalization.cts;
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;
-import android.ondevicepersonalization.OnDevicePersonalizationManager;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -33,17 +25,6 @@ import org.junit.runners.JUnit4;
*/
@RunWith(JUnit4.class)
public class OnDevicePersonalizationServiceTest {
- private Context mContext;
- private OnDevicePersonalizationManager mService;
-
- @Before
- public void setup() throws Exception {
- mContext = ApplicationProvider.getApplicationContext();
- mService = mContext.getSystemService(OnDevicePersonalizationManager.class);
- }
-
@Test
- public void testVersion() throws Exception {
- assertEquals(mService.getVersion(), "1.0");
- }
+ public void test() throws Exception {}
}
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
index 14f8516b6bc..e6c186c5787 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
@@ -25,6 +25,7 @@ import android.media.cts.InputSurface;
import android.media.cts.OutputSurface;
import android.media.cts.TestArgs;
import android.opengl.GLES20;
+import android.os.Build;
import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,6 +40,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.MediaUtils;
import org.junit.Before;
@@ -71,6 +73,7 @@ public class DecodeEditEncodeTest {
private static final boolean WORK_AROUND_BUGS = false; // avoid fatal codec bugs
private static final boolean VERBOSE = false; // lots of logging
private static final boolean DEBUG_SAVE_FILE = false; // save copy of encoded movie
+ private static final boolean IS_AFTER_T = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU);
// parameters for the encoder
private static final int FRAME_RATE = 15; // 15fps
@@ -160,13 +163,18 @@ public class DecodeEditEncodeTest {
}
@Before
- public void shouldSkip() {
+ public void shouldSkip() throws IOException {
MediaFormat format = MediaFormat.createVideoFormat(mMediaType, mWidth, mHeight);
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
assumeTrue(MediaUtils.supports(mEncoderName, format));
assumeTrue(MediaUtils.supports(mDecoderName, format));
+ // Few cuttlefish specific color conversion issues were fixed after Android T.
+ if (MediaUtils.onCuttlefish()) {
+ assumeTrue("Color conversion related tests are not valid on cuttlefish releases "
+ + "through android T for format: " + format, IS_AFTER_T);
+ }
}
@Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4})")
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
index 7780a1374f2..eff1f512eb2 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
@@ -30,6 +30,7 @@ import android.media.cts.OutputSurface;
import android.media.cts.SdkMediaCodec;
import android.media.cts.TestArgs;
import android.opengl.GLES20;
+import android.os.Build;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresDevice;
import android.util.Log;
@@ -37,6 +38,7 @@ import android.util.Log;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.ApiLevelUtil;
import com.android.compatibility.common.util.MediaUtils;
import java.io.FileOutputStream;
@@ -82,6 +84,7 @@ public class EncodeDecodeTest {
private static final boolean VERBOSE = false; // lots of logging
private static final boolean DEBUG_SAVE_FILE = false; // save copy of encoded movie
private static final String DEBUG_FILE_NAME_BASE = "/sdcard/test.";
+ private static final boolean IS_AFTER_T = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU);
// parameters for the encoder
private static final int FRAME_RATE = 15; // 15fps
@@ -283,6 +286,11 @@ public class EncodeDecodeTest {
*/
public static void runTest(EncodeDecodeTest obj, boolean persisent, boolean useNdk)
throws Throwable {
+ // Few cuttlefish specific color conversion issues were fixed after Android T.
+ if (MediaUtils.onCuttlefish()) {
+ assumeTrue("Color conversion related tests are not valid on cuttlefish releases "
+ + "through android T", IS_AFTER_T);
+ }
SurfaceToSurfaceWrapper wrapper =
new SurfaceToSurfaceWrapper(obj, persisent, useNdk);
Thread th = new Thread(wrapper, "codec test");
diff --git a/tests/tests/mediastress/AndroidTest.xml b/tests/tests/mediastress/AndroidTest.xml
index c6ed5263bc0..215d9271fb0 100644
--- a/tests/tests/mediastress/AndroidTest.xml
+++ b/tests/tests/mediastress/AndroidTest.xml
@@ -19,6 +19,14 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-test-harness" value="false" />
+ <option name="screen-always-on" value="on" />
+ <option name="screen-adaptive-brightness" value="off" />
+ <option name="disable-audio" value="false"/>
+ <option name="screen-saver" value="off"/>
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="cts" />
diff --git a/tests/tests/permission/Android.bp b/tests/tests/permission/Android.bp
index 5c861b51e30..91a9dfcfafe 100644
--- a/tests/tests/permission/Android.bp
+++ b/tests/tests/permission/Android.bp
@@ -113,6 +113,8 @@ android_test {
":CtsStorageEscalationApp29Full",
":CtsStorageEscalationApp29Scoped",
":CtsVictimPermissionDefinerApp",
+ ":CtsAppThatRequestsSystemAlertWindow22",
+ ":CtsAppThatRequestsSystemAlertWindow23",
],
per_testcase_directory: true,
}
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index 56a72c9b3f2..eafc6a6389c 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -92,6 +92,8 @@
<option name="push" value="CtsStorageEscalationApp29Full.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Full.apk" />
<option name="push" value="CtsStorageEscalationApp29Scoped.apk->/data/local/tmp/cts/permissions/CtsStorageEscalationApp29Scoped.apk" />
<option name="push" value="CtsAppThatHasNotificationListener.apk->/data/local/tmp/cts/permissions/CtsAppThatHasNotificationListener.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow22.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow22.apk" />
+ <option name="push" value="CtsAppThatRequestsSystemAlertWindow23.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsSystemAlertWindow23.apk" />
</target_preparer>
<!-- Remove additional apps if installed -->
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
new file mode 100644
index 00000000000..43cc9de97a0
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow22",
+ target_sdk_version: "22",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "22",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
new file mode 100644
index 00000000000..8b85b132a61
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow22/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission3.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
new file mode 100644
index 00000000000..403257d4554
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsAppThatRequestsSystemAlertWindow23",
+ target_sdk_version: "23",
+ certificate: ":cts-testkey2",
+ min_sdk_version: "23",
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-permission",
+ "sts",
+ ],
+}
diff --git a/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
new file mode 100644
index 00000000000..8b85b132a61
--- /dev/null
+++ b/tests/tests/permission/AppThatRequestSystemAlertWindow23/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.permission3.cts.usesystemalertwindowpermission">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+</manifest>
diff --git a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
index f88b7ecbbaa..67bb9166370 100644
--- a/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/BaseNotificationListenerCheckTest.java
@@ -433,7 +433,7 @@ public class BaseNotificationListenerCheckTest {
* @return The notification or `null` if there is none
*/
protected StatusBarNotification getNotification(boolean cancelNotification) throws Throwable {
- return NotificationUtils.getNotificationForPackageAndId(
+ return NotificationListenerUtils.getNotificationForPackageAndId(
PERMISSION_CONTROLLER_PKG,
NOTIFICATION_LISTENER_CHECK_NOTIFICATION_ID,
cancelNotification);
@@ -444,6 +444,6 @@ public class BaseNotificationListenerCheckTest {
*/
protected void clearNotifications() throws Throwable {
// Clear notification if present
- NotificationUtils.clearNotificationsForPackage(PERMISSION_CONTROLLER_PKG);
+ NotificationListenerUtils.cancelNotifications(PERMISSION_CONTROLLER_PKG);
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/NotificationListenerUtils.kt b/tests/tests/permission/src/android/permission/cts/NotificationListenerUtils.kt
index 0ee8a3db57a..dffefe790f9 100644
--- a/tests/tests/permission/src/android/permission/cts/NotificationListenerUtils.kt
+++ b/tests/tests/permission/src/android/permission/cts/NotificationListenerUtils.kt
@@ -16,16 +16,15 @@
package android.permission.cts
-import android.service.notification.StatusBarNotification
-import org.junit.Assert
import android.permission.cts.TestUtils.ensure
import android.permission.cts.TestUtils.eventually
+import android.service.notification.StatusBarNotification
+import org.junit.Assert
object NotificationListenerUtils {
private const val NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS = 5000L
private const val NOTIFICATION_WAIT_MILLIS = 2000L
- private val notificationService = NotificationListener.getInstance()
@JvmStatic
fun assertEmptyNotification(packageName: String, notificationId: Int) {
@@ -47,6 +46,7 @@ object NotificationListenerUtils {
@JvmStatic
fun cancelNotification(packageName: String, notificationId: Int) {
+ val notificationService = NotificationListener.getInstance()
val notification = getNotification(packageName, notificationId)
if (notification != null) {
notificationService.cancelNotification(notification.key)
@@ -58,6 +58,7 @@ object NotificationListenerUtils {
@JvmStatic
fun cancelNotifications(packageName: String) {
+ val notificationService = NotificationListener.getInstance()
val notifications = getNotifications(packageName)
if (notifications.isNotEmpty()) {
notifications.forEach { notification ->
@@ -79,6 +80,7 @@ object NotificationListenerUtils {
@JvmStatic
fun getNotifications(packageName: String): List<StatusBarNotification> {
val notifications: MutableList<StatusBarNotification> = ArrayList()
+ val notificationService = NotificationListener.getInstance()
for (notification in notificationService.activeNotifications) {
if (notification.packageName == packageName) {
notifications.add(notification)
@@ -86,4 +88,32 @@ object NotificationListenerUtils {
}
return notifications
}
-} \ No newline at end of file
+
+ /**
+ * Get a notification listener notification that is currently visible.
+ *
+ * @param cancelNotification if `true` the notification is canceled inside this method
+ * @return The notification or `null` if there is none
+ */
+ @JvmStatic
+ @Throws(Throwable::class)
+ fun getNotificationForPackageAndId(
+ pkg: String,
+ id: Int,
+ cancelNotification: Boolean
+ ): StatusBarNotification? {
+ val notifications: List<StatusBarNotification> = getNotifications(pkg)
+ if (notifications.isEmpty()) {
+ return null
+ }
+ for (notification in notifications) {
+ if (notification.id == id) {
+ if (cancelNotification) {
+ cancelNotification(pkg, id)
+ }
+ return notification
+ }
+ }
+ return null
+ }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NotificationUtils.kt b/tests/tests/permission/src/android/permission/cts/NotificationUtils.kt
deleted file mode 100644
index 7c50837f82b..00000000000
--- a/tests/tests/permission/src/android/permission/cts/NotificationUtils.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.permission.cts
-
-import android.service.notification.StatusBarNotification
-import org.junit.Assert
-import java.util.concurrent.TimeUnit
-
-/**
- * Utility methods to interact with NotificationManager through the CTS NotificationListenerService
- * to get or clear notifications.
- */
-object NotificationUtils {
-
- private val NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5)
-
- /**
- * Get a notification listener notification that is currently visible.
- *
- * @param cancelNotification if `true` the notification is canceled inside this method
- * @return The notification or `null` if there is none
- */
- @JvmStatic
- @Throws(Throwable::class)
- fun getNotificationForPackageAndId(
- pkg: String,
- id: Int,
- cancelNotification: Boolean
- ): StatusBarNotification? {
- val notificationService = NotificationListener.getInstance()
- val notifications: List<StatusBarNotification> = getNotificationsForPackage(pkg)
- if (notifications.isEmpty()) {
- return null
- }
- for (notification in notifications) {
- if (notification.id == id) {
- if (cancelNotification) {
- clearNotification(notification)
- }
- return notification
- }
- }
- return null
- }
-
- /**
- * Clears all currently visible notifications for a specified package.
- */
- @JvmStatic
- @Throws(Throwable::class)
- fun clearNotificationsForPackage(pkg: String) {
- val notifications: List<StatusBarNotification> = getNotificationsForPackage(pkg)
- if (notifications.isEmpty()) {
- return
- }
-
- clearNotifications(notifications)
- }
-
- /** Clears the specified notification and ensures (asserts) it was removed */
- @JvmStatic
- @Throws(Throwable::class)
- fun clearNotification(notification: StatusBarNotification) {
- val notificationService = NotificationListener.getInstance()
- notificationService.cancelNotification(notification.key)
-
- // Wait for notification to get canceled
- TestUtils.eventually({
- Assert.assertFalse(
- listOf(*notificationService.activeNotifications)
- .contains(notification)
- )
- }, NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS)
- }
-
- private fun clearNotifications(notifications: List<StatusBarNotification>) {
- val notificationService = NotificationListener.getInstance()
- notifications.forEach { notificationService.cancelNotification(it.key) }
-
- // Wait for notification to get canceled
- TestUtils.eventually({
- val activeNotifications: List<StatusBarNotification> =
- listOf(*notificationService.activeNotifications)
- Assert.assertFalse(
- activeNotifications.any { notifications.contains(it) }
- )
- }, NOTIFICATION_CANCELLATION_TIMEOUT_MILLIS)
- }
-
- /**
- * Get all notifications associated with a given package that are currently visible.
- * @param pkg Package for which to filter the notifications by
- * @return [List] of [StatusBarNotification]
- */
- @Throws(Exception::class)
- private fun getNotificationsForPackage(pkg: String): List<StatusBarNotification> {
- val notificationService = NotificationListener.getInstance()
- val notifications: MutableList<StatusBarNotification> = ArrayList()
- for (notification in notificationService.activeNotifications) {
- if (notification.packageName == pkg) {
- notifications.add(notification)
- }
- }
- return notifications
- }
-} \ No newline at end of file
diff --git a/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
new file mode 100644
index 00000000000..fe5373e1c37
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/RevokeSawPermissionTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission.cts
+
+import android.content.pm.PackageManager
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.SystemUtil
+import org.junit.After
+import org.junit.Assert
+import org.junit.Test
+
+private val APP_PKG_NAME = "android.permission3.cts.usesystemalertwindowpermission"
+private val APK_22 = "/data/local/tmp/cts/permissions/" +
+ "CtsAppThatRequestsSystemAlertWindow22.apk"
+private val APK_23 = "/data/local/tmp/cts/permissions/" +
+ "CtsAppThatRequestsSystemAlertWindow23.apk"
+
+class RevokeSawPermissionTest {
+
+ fun installApp(apk: String) {
+ SystemUtil.runShellCommand("pm install -r $apk")
+ }
+
+ @After
+ fun uninstallApp() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
+ }
+
+ @AsbSecurityTest(cveBugId = [247512334L])
+ @Test
+ fun testPre23AppsWithSystemAlertWindowGetDeniedOnUpgrade() {
+ installApp(APK_22)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, true)
+ installApp(APK_23)
+ assertAppHasPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, false)
+ }
+
+ private fun assertAppHasPermission(permissionName: String, expectPermission: Boolean) {
+ Assert.assertEquals(
+ if (expectPermission) {
+ PackageManager.PERMISSION_GRANTED
+ } else {
+ PackageManager.PERMISSION_DENIED
+ },
+ InstrumentationRegistry.getInstrumentation().getTargetContext().packageManager
+ .checkPermission(permissionName, APP_PKG_NAME)
+ )
+ }
+}
diff --git a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
index d5bd49bdf37..47faaa65c46 100644
--- a/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
+++ b/tests/tests/permission4/src/android/permission4/cts/CameraMicIndicatorsPermissionTest.kt
@@ -92,8 +92,12 @@ class CameraMicIndicatorsPermissionTest {
private val isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
private val isCar = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
- private val micLabel = getPermissionControllerString(MIC_LABEL_NAME)
- private val cameraLabel = getPermissionControllerString(CAMERA_LABEL_NAME)
+ private val safetyCenterMicLabel = getPermissionControllerString(MIC_LABEL_NAME)
+ private val safetyCenterCameraLabel = getPermissionControllerString(CAMERA_LABEL_NAME)
+ private val cameraLabel = packageManager.getPermissionGroupInfo(
+ Manifest.permission_group.CAMERA, 0).loadLabel(packageManager).toString().toLowerCase()
+ private val micLabel = packageManager.getPermissionGroupInfo(
+ Manifest.permission_group.MICROPHONE, 0).loadLabel(packageManager).toString().toLowerCase()
private var wasEnabled = false
private var isScreenOn = false
private var screenTimeoutBeforeTest: Long = 0L
@@ -120,8 +124,6 @@ class CameraMicIndicatorsPermissionTest {
Settings.System.putLong(
context.contentResolver, Settings.System.SCREEN_OFF_TIMEOUT, 1800000L
)
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
- SAFETY_CENTER_ENABLED, false.toString(), false)
}
if (!isScreenOn) {
@@ -407,22 +409,28 @@ class CameraMicIndicatorsPermissionTest {
return@eventually
}
if (useMic) {
+ var micIdentifier: String
var iconView = if (safetyCenterEnabled) {
- waitFindObjectOrNull(By.text(micLabel))
+ micIdentifier = safetyCenterMicLabel
+ waitFindObject(By.text(micIdentifier))
} else {
- uiDevice.findObject(UiSelector().descriptionContains(micLabel))
+ micIdentifier = micLabel
+ waitFindObject(By.descContains(micIdentifier))
}
- assertNotNull("View with description $micLabel not found", iconView)
+ assertNotNull("View with text/description $micIdentifier not found", iconView)
}
if (useCamera) {
+ var camIdentifier: String
var iconView = if (safetyCenterEnabled) {
- waitFindObjectOrNull(By.text(cameraLabel))
+ camIdentifier = safetyCenterCameraLabel
+ waitFindObject(By.text(camIdentifier))
} else {
- uiDevice.findObject(UiSelector().descriptionContains(cameraLabel))
+ camIdentifier = cameraLabel
+ waitFindObject(By.descContains(camIdentifier))
}
- assertNotNull("View with text $APP_LABEL not found", iconView)
+ assertNotNull("View with text/description $camIdentifier not found", iconView)
}
- var appView = waitFindObjectOrNull(By.textContains(APP_LABEL))
+ var appView = waitFindObject(By.textContains(APP_LABEL))
assertNotNull("View with text $APP_LABEL not found", appView)
if (safetyCenterEnabled) {
assertTrue("Did not find safety center views",
@@ -456,11 +464,11 @@ class CameraMicIndicatorsPermissionTest {
}
if (safetyCenterEnabled) {
- var micView = waitFindObjectOrNull(By.text(micLabel))
+ var micView = waitFindObject(By.text(safetyCenterMicLabel))
assertNotNull("View with text $micLabel not found", micView)
- var camView = waitFindObjectOrNull(By.text(cameraLabel))
+ var camView = waitFindObject(By.text(safetyCenterCameraLabel))
assertNotNull("View with text $cameraLabel not found", camView)
- var shellView = waitFindObjectOrNull(By.textContains(shellLabel))
+ var shellView = waitFindObject(By.textContains(shellLabel))
assertNotNull("View with text $shellLabel not found", shellView)
} else {
val usageViews = uiDevice.findObjects(By.res(PRIVACY_ITEM_ID))
@@ -516,9 +524,9 @@ class CameraMicIndicatorsPermissionTest {
assumeTrue(isSafetyCenterEnabled)
}
- protected fun waitFindObjectOrNull(selector: BySelector): UiObject2? {
+ protected fun waitFindObject(selector: BySelector): UiObject2? {
waitForIdle()
- return findObjectWithRetry({ t -> UiAutomatorUtils.waitFindObjectOrNull(selector, t) })
+ return findObjectWithRetry({ t -> UiAutomatorUtils.waitFindObject(selector, t) })
}
private fun findObjectWithRetry(
@@ -551,4 +559,4 @@ class CameraMicIndicatorsPermissionTest {
throw RuntimeException(e)
}
}
-} \ No newline at end of file
+}
diff --git a/tests/tests/security/Android.bp b/tests/tests/security/Android.bp
index 0cf3dd54c6b..9f4cda5752c 100644
--- a/tests/tests/security/Android.bp
+++ b/tests/tests/security/Android.bp
@@ -33,6 +33,7 @@ android_test {
"compatibility-common-util-devicesidelib",
"guava",
"platform-test-annotations",
+ "permission-test-util-lib",
"sts-device-util",
"hamcrest-library",
"NeneInternal",
@@ -80,7 +81,17 @@ android_test {
":CtsDeviceInfo",
":RolePermissionOverrideTestApp",
":SplitBluetoothPermissionTestApp",
- ],
+ ":CtsPermissionBackupAppCert1",
+ ":CtsPermissionBackupAppCert1Dup",
+ ":CtsPermissionBackupAppCert2",
+ ":CtsPermissionBackupAppCert3",
+ ":CtsPermissionBackupAppCert4",
+ ":CtsPermissionBackupAppCert12",
+ ":CtsPermissionBackupAppCert12Dup",
+ ":CtsPermissionBackupAppCert34",
+ ":CtsPermissionBackupAppCert123",
+ ":CtsPermissionBackupAppCert4History124",
+ ],
}
android_test_helper_app {
@@ -89,6 +100,95 @@ android_test_helper_app {
manifest: "testdata/packageinstallertestapp.xml",
}
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert1",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-1",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert1Dup",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-1",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert2",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-2",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert3",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-3",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert4",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-4",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert12",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-1",
+ additional_certificates: [
+ ":permission-test-cert-2",
+ ],
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert12Dup",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-1",
+ additional_certificates: [
+ ":permission-test-cert-2",
+ ],
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert34",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-3",
+ additional_certificates: [
+ ":permission-test-cert-4",
+ ],
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert123",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-1",
+ additional_certificates: [
+ ":permission-test-cert-2",
+ ":permission-test-cert-3",
+ ],
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "CtsPermissionBackupAppCert4History124",
+ min_sdk_version: "30",
+ certificate: ":permission-test-cert-4",
+ additional_certificates: [
+ ":permission-test-cert-1",
+
+ ],
+ rotationMinSdkVersion: "30",
+ lineage: ":permission-test-cert-with-rotation-history",
+ manifest: "testdata/permissionbackuptestapp/AndroidManifest.xml",
+}
+
android_app_certificate {
name: "security_cts_test_certificate",
certificate: "security_cts_test_cert",
@@ -98,3 +198,30 @@ android_test_helper_app {
name: "RolePermissionOverrideTestApp",
manifest: "testdata/rolepermissionoverridetestapp.xml",
}
+
+android_app_certificate {
+ name: "permission-test-cert-1",
+ certificate: "test-cert-1",
+}
+
+android_app_certificate {
+ name: "permission-test-cert-2",
+ certificate: "test-cert-2",
+}
+
+android_app_certificate {
+ name: "permission-test-cert-3",
+ certificate: "test-cert-3",
+}
+
+android_app_certificate {
+ name: "permission-test-cert-4",
+ certificate: "test-cert-4",
+}
+
+filegroup {
+ name: "permission-test-cert-with-rotation-history",
+ srcs: [
+ "test-cert-with-1-2-4-in-rotation-history",
+ ],
+}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 4ddeca0e23c..72a110b40d6 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.security.cts">
+ <permission-tree android:name="com.android.cts"/>
+
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
@@ -201,9 +203,34 @@
</intent-filter>
</activity>
+ <receiver android:name="android.security.cts.CVE_2022_20420.PocDeviceAdminReceiver"
+ android:exported="true"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin_CVE_2022_20420" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
<activity android:name="android.security.cts.ActivityManagerTest$ActivityOptionsActivity" />
<activity android:name="android.security.cts.ActivityManagerTest$BaseActivity" />
+ <provider android:name="android.security.cts.CVE_2022_20358.PocContentProvider"
+ android:authorities="android.security.cts.CVE_2022_20358.provider"
+ android:enabled="true"
+ android:exported="true" />
+
+ <service android:name="android.security.cts.CVE_2022_20358.PocSyncService"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.content.SyncAdapter" />
+ </intent-filter>
+ <meta-data android:name="android.content.SyncAdapter"
+ android:resource="@xml/syncadapter" />
+ </service>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 9bd5eb7e0a8..73e6bc7ece8 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -52,6 +52,16 @@
<option name="cleanup" value="true" />
<option name="push" value="RolePermissionOverrideTestApp.apk->/data/local/tmp/cts/security/RolePermissionOverrideTestApp.apk" />
<option name="push" value="SplitBluetoothPermissionTestApp.apk->/data/local/tmp/cts/security/SplitBluetoothPermissionTestApp.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert1.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert1Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert1Dup.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert2.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert2.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert3.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert3.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert4.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert12.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert12Dup.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert12Dup.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert123.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert123.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert34.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert34.apk" />
+ <option name="push" value="CtsPermissionBackupAppCert4History124.apk->/data/local/tmp/cts/security/CtsPermissionBackupAppCert4History124.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
@@ -61,4 +71,9 @@
<option name="test-timeout" value="900000" />
<option name="hidden-api-checks" value="false" />
</test>
+
+ <target_preparer class="android.cts.backup.BackupPreparer">
+ <option name="enable-backup-if-needed" value="true" />
+ <option name="select-local-transport" value="true" />
+ </target_preparer>
</configuration>
diff --git a/tests/tests/security/res/raw/cve_2022_25669.3gp b/tests/tests/security/res/raw/cve_2022_25669.3gp
new file mode 100644
index 00000000000..f5ba05ad9aa
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2022_25669.3gp
Binary files differ
diff --git a/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
new file mode 100644
index 00000000000..cb567e31d4e
--- /dev/null
+++ b/tests/tests/security/res/xml/device_admin_CVE_2022_20420.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<device-admin>
+ <uses-policies>
+ </uses-policies>
+</device-admin>
diff --git a/tests/tests/security/res/xml/syncadapter.xml b/tests/tests/security/res/xml/syncadapter.xml
new file mode 100644
index 00000000000..478fad5327f
--- /dev/null
+++ b/tests/tests/security/res/xml/syncadapter.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accountType="CVE_2022_20358_acc"
+ android:isAlwaysSyncable="true" />
diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
index 397c0129661..7bb74ffee8c 100644
--- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
+++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
@@ -18,28 +18,24 @@ package android.security.cts;
import static org.junit.Assert.fail;
-import android.app.Activity;
+import android.annotation.SuppressLint;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.platform.test.annotations.AsbSecurityTest;
import android.view.AbsSavedState;
import android.view.View;
-import android.view.View.BaseSavedState;
-import android.annotation.SuppressLint;
+
import androidx.test.runner.AndroidJUnit4;
import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.util.Random;
-
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
-import android.security.cts.R;
-import android.platform.test.annotations.AsbSecurityTest;
+import java.lang.reflect.Field;
+import java.util.Random;
@RunWith(AndroidJUnit4.class)
public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
@@ -601,6 +597,95 @@ public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
testAmbiguator(ambiguator);
}
+ /*
+ * b/240138294
+ */
+ @AsbSecurityTest(cveBugId = 240138294)
+ @Test
+ public void test_lazyValueNegativeLength() throws Exception {
+ Ambiguator ambiguator = new Ambiguator() {
+ @Override
+ public Bundle make(Bundle preReSerialize, Bundle postReSerialize) {
+ // Find key that has hash below everything else
+ Random random = new Random(1234);
+ int minHash = 0;
+ for (String s : preReSerialize.keySet()) {
+ minHash = Math.min(minHash, s.hashCode());
+ }
+ for (String s : postReSerialize.keySet()) {
+ minHash = Math.min(minHash, s.hashCode());
+ }
+
+ String negativePrefix, positivePrefix;
+ // When read as value, jump back to the start of the header (8 bytes)
+ negativePrefix = getStringEncodingInt(-8);
+ // Size of the malicious bundle before the 'cmd' key
+ positivePrefix = getStringEncodingInt(48);
+
+ String key1, key2, key3;
+ int key1Hash, key2Hash, key3Hash;
+
+ do {
+ key1 = randomString(random);
+ // 16 characters total, will be read as type parcelable array when
+ // read as value
+ key2 = negativePrefix + randomString(random, 14);
+ key3 = positivePrefix + randomString(random, 14);
+ key1Hash = key1.hashCode();
+ key2Hash = key3.hashCode(); // 2 and 3 are swapped
+ key3Hash = key2.hashCode();
+ } while (!(key1Hash < key2Hash && key2Hash < key3Hash && key3Hash < minHash));
+
+ // Pad bundles - ensures keys are in right hash order
+ padBundle(postReSerialize, preReSerialize.size() + 2, minHash, random);
+ padBundle(preReSerialize, postReSerialize.size() - 2, minHash, random);
+
+ // Write bundle
+ Parcel parcel = Parcel.obtain();
+
+ int sizePosition = parcel.dataPosition();
+ parcel.writeInt(0);
+ parcel.writeInt(BUNDLE_MAGIC_NATIVE);
+ int startPosition = parcel.dataPosition();
+
+ parcel.writeInt(preReSerialize.size() + 3); // Num key-value pairs
+
+ parcel.writeString(key1); // Key 1
+ parcel.writeString(key2); // Value 1/Key 2
+ parcel.writeInt(VAL_NULL);
+ parcel.writeString(key3);
+ parcel.writeInt(VAL_BUNDLE);
+ parcel.writeBundle(postReSerialize); // Value 3
+
+ // Data from preReSerialize bundle
+ writeBundleSkippingHeaders(parcel, preReSerialize);
+
+ // Fix up bundle size
+ int bundleDataSize = parcel.dataPosition() - startPosition;
+ parcel.setDataPosition(sizePosition);
+ parcel.writeInt(bundleDataSize);
+
+ parcel.setDataPosition(0);
+ Bundle bundle = parcel.readBundle();
+ parcel.recycle();
+ return bundle;
+ }
+
+ private String getStringEncodingInt(int i) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInt(2);
+ parcel.writeInt(i);
+ parcel.writeInt(0);
+ parcel.setDataPosition(0);
+ String s = parcel.readString();
+ parcel.recycle();
+ return s;
+ }
+ };
+
+ testAmbiguator(ambiguator);
+ }
+
private void testAmbiguator(Ambiguator ambiguator) {
Bundle bundle;
Bundle verifyMe = new Bundle();
@@ -653,6 +738,7 @@ public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
protected static final int PROCSTATS_SPARSE_MAPPING_TABLE_ARRAY_SIZE = 4096;
protected static final int BUNDLE_MAGIC = 0x4C444E42;
+ protected static final int BUNDLE_MAGIC_NATIVE = 0x4C444E44; // 'B' 'N' 'D' 'N'
protected static final int INNER_BUNDLE_PADDING = 1;
protected Field parcelledDataField;
@@ -711,8 +797,12 @@ public class AmbiguousBundlesTest extends StsExtraBusinessLogicTestCase {
}
protected static String randomString(Random random) {
+ return randomString(random, 6);
+ }
+
+ protected static String randomString(Random random, int len) {
StringBuilder b = new StringBuilder();
- for (int i = 0; i < 6; i++) {
+ for (int i = 0; i < len; i++) {
b.append((char)(' ' + random.nextInt('~' - ' ' + 1)));
}
return b.toString();
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java
new file mode 100644
index 00000000000..b1ff1688ced
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/CVE_2022_20358.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.accounts.Account;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ISyncAdapter;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20358 extends StsExtraBusinessLogicTestCase implements ServiceConnection {
+ static final int TIMEOUT_SEC = 10;
+ Semaphore mWaitResultServiceConn;
+ boolean mIsAssumeFail = false;
+ String mAssumeFailMsg = "";
+
+ @AsbSecurityTest(cveBugId = 203229608)
+ @Test
+ public void testPocCVE_2022_20358() {
+ try {
+ // Bind to the PocSyncService
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ Context context = instrumentation.getContext();
+ Intent intent = new Intent(context, PocSyncService.class);
+ intent.setAction("android.content.SyncAdapter");
+ CompletableFuture<String> callbackReturn = new CompletableFuture<>();
+ RemoteCallback cb = new RemoteCallback((Bundle result) -> {
+ callbackReturn.complete(result.getString("fail"));
+ });
+ intent.putExtra("callback", cb);
+ context.bindService(intent, this, Context.BIND_AUTO_CREATE);
+
+ // Wait for some result from the PocSyncService
+ mWaitResultServiceConn = new Semaphore(0);
+ assumeTrue(mWaitResultServiceConn.tryAcquire(TIMEOUT_SEC, TimeUnit.SECONDS));
+ assumeTrue(mAssumeFailMsg, !mIsAssumeFail);
+
+ // Wait for a result to be set from onPerformSync() of PocSyncAdapter
+ callbackReturn.get(TIMEOUT_SEC, TimeUnit.SECONDS);
+
+ // In presence of vulnerability, the above call succeeds and TimeoutException is not
+ // triggered so failing the test
+ fail("Vulnerable to b/203229608!!");
+ } catch (Exception e) {
+ if (e instanceof TimeoutException) {
+ // The fix is present so returning from here
+ return;
+ }
+ assumeNoException(e);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ try {
+ if (mWaitResultServiceConn == null) {
+ mWaitResultServiceConn = new Semaphore(0);
+ }
+ ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+ Account account = new Account("CVE_2022_20358_user", "CVE_2022_20358_acc");
+ adapter.startSync(null, "android.security.cts.CVE_2022_20358.provider", account, null);
+ mWaitResultServiceConn.release();
+ } catch (Exception e) {
+ try {
+ mWaitResultServiceConn.release();
+ mAssumeFailMsg = e.getMessage();
+ mIsAssumeFail = true;
+ } catch (Exception ex) {
+ // ignore all exceptions
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ try {
+ mWaitResultServiceConn.release();
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
new file mode 100644
index 00000000000..0bc8c2c5fed
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocContentProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class PocContentProvider extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
new file mode 100644
index 00000000000..08fbf92d8e5
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20358/PocSyncService.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20358;
+
+import android.accounts.Account;
+import android.app.Service;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+
+public class PocSyncService extends Service {
+ private static PocSyncAdapter sSyncAdapter = null;
+ private static final Object sSyncAdapterLock = new Object();
+ RemoteCallback mCb;
+
+ @Override
+ public void onCreate() {
+ try {
+ synchronized (sSyncAdapterLock) {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new PocSyncAdapter(this);
+ }
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ try {
+ mCb = (RemoteCallback) intent.getExtra("callback");
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+
+ public class PocSyncAdapter extends AbstractThreadedSyncAdapter {
+
+ public PocSyncAdapter(Context context) {
+ super(context, false);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ try {
+ if (account.type.equals("CVE_2022_20358_acc")
+ && account.name.equals("CVE_2022_20358_user")) {
+ Bundle res = new Bundle();
+ res.putString("fail", "");
+ mCb.sendResult(res);
+ }
+ } catch (Exception e) {
+ // ignore all exceptions
+ }
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
new file mode 100644
index 00000000000..35d576e5142
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/CVE_2022_20420.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20420;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IDeviceIdleController;
+import android.os.PowerExemptionManager;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20420 extends StsExtraBusinessLogicTestCase {
+ private static final int TIMEOUT_MS = 10000;
+ private static final int USER_ID = 0;
+ private Context mContext;
+ private DevicePolicyManager mPolicyManager;
+ private ComponentName mComponentName;
+ private UiAutomation mAutomation;
+
+ @After
+ public void tearDown() {
+ try {
+ mAutomation.dropShellPermissionIdentity();
+ mPolicyManager.removeActiveAdmin(mComponentName);
+ } catch (Exception ignored) {
+ // ignore all exceptions as the test has been completed.
+ }
+ }
+
+ @AsbSecurityTest(cveBugId = 238377411)
+ @Test
+ public void testDeviceAdminAppRestricted() {
+ try {
+ // Add test app to Power Save Whitelist.
+ mContext = getInstrumentation().getTargetContext();
+ mAutomation = getInstrumentation().getUiAutomation();
+ mAutomation.adoptShellPermissionIdentity(android.Manifest.permission.DEVICE_POWER,
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ IDeviceIdleController mDeviceIdleService =
+ IDeviceIdleController.Stub.asInterface(ServiceManager.getService("deviceidle"));
+ mDeviceIdleService.addPowerSaveWhitelistApp(mContext.getPackageName());
+
+ // Set test app as "Active Admin".
+ mPolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+ mComponentName = new ComponentName(mContext, PocDeviceAdminReceiver.class);
+ mPolicyManager.setActiveAdmin(mComponentName, true, USER_ID);
+ CompletableFuture<Boolean> future = new CompletableFuture<>();
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ future.complete(true);
+ }
+ };
+ mContext.registerReceiver(broadcastReceiver,
+ new IntentFilter("broadcastCVE_2022_20420"));
+ future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+ // Call vulnerable function getBackgroundRestrictionExemptionReason()
+ ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
+ int reason = activityManager.getBackgroundRestrictionExemptionReason(Process.myUid());
+ assumeTrue(
+ "Reason code other than REASON_ACTIVE_DEVICE_ADMIN/REASON_ALLOWLISTED_PACKAGE"
+ + " returned by getBackgroundRestrictionExemptionReason() = " + reason,
+ reason == PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN
+ || reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+ assertFalse("Vulnerable to b/238377411 !!",
+ reason == PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
new file mode 100644
index 00000000000..c9c1b6f13be
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20420/PocDeviceAdminReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20420;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class PocDeviceAdminReceiver extends DeviceAdminReceiver {
+
+ @Override
+ public void onEnabled(Context context, Intent intent) {
+ try {
+ context.sendBroadcast(new Intent("broadcastCVE_2022_20420"));
+ } catch (Exception e) {
+ // ignore all exceptions.
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
new file mode 100644
index 00000000000..af581a1a54d
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CVE_2022_20452.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This PoC has been written taking reference from:
+// File: frameworks/base/core/tests/coretests/src/android/os/BundleTest.java
+// Function: readFromParcelWithRwHelper_whenThrowingAndDefusing_returnsNull()
+
+package android.security.cts.CVE_2022_20452;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeNoException;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.platform.test.annotations.AsbSecurityTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2022_20452 extends StsExtraBusinessLogicTestCase {
+
+ @AsbSecurityTest(cveBugId = 240138318)
+ @Test
+ public void testPocCVE_2022_20452() {
+ try {
+ // Create a bundle with some parcelable object and a random string
+ Bundle bundle = new Bundle();
+ Parcelable parcelable = new CustomParcelable();
+ bundle.putParcelable("keyParcelable", parcelable);
+ bundle.putString("keyStr", "valStr");
+
+ // Read bundle contents into a parcel and also set read write helper for the parcel
+ Parcel parcelledBundle = Parcel.obtain();
+ bundle.writeToParcel(parcelledBundle, 0);
+ parcelledBundle.setDataPosition(0);
+ parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());
+
+ // First set 'shouldDefuse' to true, then read contents of parcel into a bundle.
+ // In presence of fix, this will cause a ClassNotFoundException because bundle will not
+ // be able to find the class for 'CustomParcelable' as the class loader is not set, so
+ // Parcel will not be read properly and the code will return without reading the string.
+ Bundle.setShouldDefuse(true);
+ Bundle testBundle = new Bundle();
+ testBundle.readFromParcel(parcelledBundle);
+
+ // If the vulnerability is active, we will be able to read string from bundle.
+ assertNull("Vulnerable to b/240138318 !!", testBundle.getString("keyStr"));
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
new file mode 100644
index 00000000000..f076eee6535
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2022_20452/CustomParcelable.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20452;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class CustomParcelable implements Parcelable {
+ private boolean mDummyValue = true;
+
+ CustomParcelable() {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mDummyValue);
+ }
+
+ public static final Creator<CustomParcelable> CREATOR =
+ new Creator<CustomParcelable>() {
+ @Override
+ public CustomParcelable createFromParcel(Parcel in) {
+ return new CustomParcelable();
+ }
+
+ @Override
+ public CustomParcelable[] newArray(int size) {
+ return new CustomParcelable[size];
+ }
+ };
+}
diff --git a/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
new file mode 100644
index 00000000000..11709395f75
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PermissionBackupCertificateCheckTest.kt
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package android.security.cts
+
+import android.Manifest.permission.*
+import android.app.AppOpsManager
+import android.content.pm.PackageManager.*
+import android.os.ParcelFileDescriptor
+import android.permission.cts.PermissionUtils.grantPermission
+import android.platform.test.annotations.AppModeFull
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compatibility.common.util.BackupUtils
+import com.android.compatibility.common.util.BackupUtils.LOCAL_TRANSPORT_TOKEN
+import com.android.compatibility.common.util.BusinessLogicTestCase
+import com.android.compatibility.common.util.ShellUtils.runShellCommand
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import java.io.InputStream
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests that permissions for backed up apps are restored only after checking that their signing
+ * certificates are compared.
+ *
+ * @see [com.android.permissioncontroller.permission.service.BackupHelper]
+ */
+@AppModeFull
+@RunWith(AndroidJUnit4::class)
+class PermissionBackupCertificateCheckTest : StsExtraBusinessLogicTestCase() {
+ private val backupUtils: BackupUtils =
+ object : BackupUtils() {
+ override fun executeShellCommand(command: String): InputStream {
+ val pfd =
+ BusinessLogicTestCase.getInstrumentation()
+ .uiAutomation
+ .executeShellCommand(command)
+ return ParcelFileDescriptor.AutoCloseInputStream(pfd)
+ }
+ }
+
+ private var isBackupSupported = false
+
+ private val targetContext = InstrumentationRegistry.getTargetContext()
+
+ @Before
+ fun setUp() {
+ val packageManager = BusinessLogicTestCase.getInstrumentation().context.packageManager
+ isBackupSupported =
+ (packageManager != null && packageManager.hasSystemFeature(FEATURE_BACKUP))
+
+ if (isBackupSupported) {
+ assertTrue("Backup not enabled", backupUtils.isBackupEnabled)
+ assertTrue("LocalTransport not selected", backupUtils.isLocalTransportSelected)
+ backupUtils.executeShellCommandSync("setprop log.tag.$APP_LOG_TAG VERBOSE")
+ }
+ }
+
+ @After
+ fun tearDown() {
+ uninstallIfInstalled(APP)
+ clearFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+ clearFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has the
+ * same certificate as the backed up app.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_sameCert_restoresRuntimePermissions() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1_DUP)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has a
+ * different certificate as the backed up app.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_diffCert_doesNotGrantRuntimePermissions() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_3)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has the
+ * backed up app's certificate in its signing history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_midHistoryToRotated_restoresRuntimePermissions() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has the
+ * backed up app's certificate as the original certificate in its signing history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_origToRotated_restoresRuntimePermissions() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app has the
+ * restored app's certificate in its signing history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_rotatedToMidHistory_restoresRuntimePermissions() {
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app has the
+ * restored app's certificate in its signing history as its original certificate.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_rotatedToOrig_restoresRuntimePermissions() {
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app has the same
+ * certificate as the restored app, but the restored app additionally has signing certificate
+ * history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_sameWithHistory_restoresRuntimePermissions() {
+ install(APP_APK_CERT_4)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app has the same
+ * certificate as the restored app, but the backed up app additionally has signing certificate
+ * history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_sameWithoutHistory_restoresRuntimePermissions() {
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has
+ * signing history, but the backed up app's certificate is not in this signing history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_notInBackedUpHistory_doesNotRestoreRuntimePerms() {
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_3)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has
+ * signing history, but the backed up app's certificate is not in this signing history.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_notInRestoredHistory_doesNotRestoreRuntimePerms() {
+ install(APP_APK_CERT_3)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has
+ * multiple certificates, and the backed up app also has identical multiple certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_sameMultCerts_restoresRuntimePermissions() {
+ install(APP_APK_CERT_1_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1_2_DUP)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has
+ * multiple certificates, and the backed up app do not have identical multiple certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_diffMultCerts_doesNotRestoreRuntimePermissions() {
+ install(APP_APK_CERT_1_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_3_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the app being restored has
+ * multiple certificates, and the backed up app's certificate is present in th restored app's
+ * certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_singleToMultiCert_restoresRuntimePerms() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1_2_3)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app and the app
+ * being restored have multiple certificates, and the backed up app's certificates are a subset
+ * of the restored app's certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_multCertsToSuperset_doesNotRestoreRuntimePerms() {
+ install(APP_APK_CERT_1_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1_2_3)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of regular runtime permissions, when the backed up app and the app
+ * being restored have multiple certificates, and the backed up app's certificates are a
+ * superset of the restored app's certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_multCertsToSubset_doesNotRestoreRuntimePermissions() {
+ install(APP_APK_CERT_1_2_3)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_1_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, READ_CONTACTS))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when both foreground and background runtime
+ * permissions are not granted and the backed up and restored app have compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgBgDenied_matchingCerts_restoresFgBgPermissions() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ // Make a token change to permission state, to enable to us to determine when restore is
+ // complete.
+ grantPermission(APP, WRITE_CONTACTS)
+ // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+ // to ensure that permissions are backed up.
+ setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+ setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+
+ // Wait until restore is complete.
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, WRITE_CONTACTS))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when both foreground and background runtime
+ * permissions are not granted and the backed up and restored app don't have compatible
+ * certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgBgDenied_notMatchingCerts_doesNotRestorePerms() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ // Make a token change to permission state, to enable to us to determine when restore is
+ // complete.
+ grantPermission(APP, WRITE_CONTACTS)
+ // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+ // to ensure that permissions are backed up.
+ setFlag(APP, ACCESS_FINE_LOCATION, FLAG_PERMISSION_USER_SET)
+ setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+
+ // Wait until restore is complete.
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, WRITE_CONTACTS))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when foreground runtime permission is
+ * granted and the backed up and restored app have compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgGranted_matchingCerts_restoresFgBgPermissions() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+ // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+ // to ensure that permissions are backed up.
+ setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_FOREGROUND, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when foreground runtime permission is
+ * granted and the backed up and restored app don't have compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgGranted_notMatchingCerts_doesNotRestoreFgBgPerms() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+ // PERMISSION_DENIED is the default state, so we mark the permissions as user set in order
+ // to ensure that permissions are backed up.
+ setFlag(APP, ACCESS_BACKGROUND_LOCATION, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when foreground and background runtime
+ * permissions are granted and the backed up and restored app have compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgBgGranted_matchingCerts_restoresFgBgPermissions() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+ grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_ALLOWED, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of tri-state permissions, when foreground and background runtime
+ * permissions are granted and the backed up and restored app don't have compatible
+ * certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_fgBgGranted_notMatchingCerts_restoresFgBgPerms() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+ grantPermission(APP, ACCESS_BACKGROUND_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually {
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION))
+ assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_BACKGROUND_LOCATION))
+ assertEquals(AppOpsManager.MODE_IGNORED, getAppOp(APP, ACCESS_FINE_LOCATION))
+ }
+ }
+
+ /**
+ * Test backup and restore of flags when the backed up app and restored app have compatible
+ * certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_matchingCerts_restoresFlags() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually { assertTrue(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+ }
+
+ /**
+ * Test backup and restore of flags when the backed up app and restored app don't have
+ * compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_notMatchingCerts_doesNotRestoreFlag() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ setFlag(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ install(APP_APK_CERT_2)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+
+ eventually { assertFalse(isFlagSet(APP, WRITE_CONTACTS, FLAG_PERMISSION_USER_SET)) }
+ }
+
+ /**
+ * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+ * after restore has run, and the backed up app and restored app have compatible certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_appInstalledLater_matchingCerts_restoresCorrectly() {
+ install(APP_APK_CERT_2)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+ eventually { assertEquals(PERMISSION_GRANTED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+ }
+
+ /**
+ * Test backup and delayed restore of regular runtime permission, i.e. when an app is installed
+ * after restore has run, and the backed up app and restored app don't have compatible
+ * certificates.
+ */
+ @Test
+ @AsbSecurityTest(cveBugId = [184847040])
+ fun testRestore_appInstalledLater_notMatchingCerts_doesNotRestore() {
+ install(APP_APK_CERT_1)
+ if (!isBackupSupported) {
+ return
+ }
+ grantPermission(APP, ACCESS_FINE_LOCATION)
+
+ backupUtils.backupNowAndAssertSuccess(ANDROID_PACKAGE)
+ uninstallIfInstalled(APP)
+ backupUtils.restoreAndAssertSuccess(LOCAL_TRANSPORT_TOKEN, ANDROID_PACKAGE)
+ install(APP_APK_CERT_4_HISTORY_1_2_4)
+
+ eventually { assertEquals(PERMISSION_DENIED, checkPermission(APP, ACCESS_FINE_LOCATION)) }
+ }
+
+ private fun install(apk: String) {
+ val output = runShellCommand("pm install -r $apk")
+ assertEquals("Success", output)
+ }
+
+ private fun uninstallIfInstalled(packageName: String) {
+ runShellCommand("pm uninstall $packageName")
+ }
+
+ private fun setFlag(app: String, permission: String, flag: Int) {
+ runWithShellPermissionIdentity {
+ targetContext.packageManager.updatePermissionFlags(
+ permission, app, flag, flag, targetContext.user)
+ }
+ }
+
+ private fun clearFlag(app: String, permission: String, flag: Int) {
+ runWithShellPermissionIdentity {
+ targetContext.packageManager.updatePermissionFlags(
+ permission, app, flag, 0, targetContext.user)
+ }
+ }
+
+ private fun isFlagSet(app: String, permission: String, flag: Int): Boolean {
+ return try {
+ callWithShellPermissionIdentity<Int> {
+ targetContext.packageManager.getPermissionFlags(permission, app, targetContext.user)
+ } and flag == flag
+ } catch (e: Exception) {
+ throw RuntimeException(e)
+ }
+ }
+
+ private fun checkPermission(app: String, permission: String): Int {
+ return targetContext.packageManager.checkPermission(permission, app)
+ }
+
+ private fun getAppOp(app: String, permission: String): Int {
+ return try {
+ callWithShellPermissionIdentity {
+ targetContext
+ .getSystemService<AppOpsManager>(AppOpsManager::class.java)!!
+ .unsafeCheckOpRaw(
+ AppOpsManager.permissionToOp(permission)!!,
+ targetContext.packageManager.getPackageUid(app, 0),
+ app)
+ }
+ } catch (e: Exception) {
+ throw RuntimeException(e)
+ }
+ }
+
+ companion object {
+ /** The name of the package of the apps under test */
+ private const val APP = "android.security.permissionbackup"
+ /** The apk of the packages */
+ private const val APK_PATH = "/data/local/tmp/cts/security/"
+ private const val APP_APK_CERT_1 = "${APK_PATH}CtsPermissionBackupAppCert1.apk"
+ private const val APP_APK_CERT_1_DUP = "${APK_PATH}CtsPermissionBackupAppCert1Dup.apk"
+ private const val APP_APK_CERT_2 = "${APK_PATH}CtsPermissionBackupAppCert2.apk"
+ private const val APP_APK_CERT_3 = "${APK_PATH}CtsPermissionBackupAppCert3.apk"
+ private const val APP_APK_CERT_4 = "${APK_PATH}CtsPermissionBackupAppCert4.apk"
+ private const val APP_APK_CERT_1_2 = "${APK_PATH}CtsPermissionBackupAppCert12.apk"
+ private const val APP_APK_CERT_1_2_DUP = "${APK_PATH}CtsPermissionBackupAppCert12Dup.apk"
+ private const val APP_APK_CERT_1_2_3 = "${APK_PATH}CtsPermissionBackupAppCert123.apk"
+ private const val APP_APK_CERT_3_4 = "${APK_PATH}CtsPermissionBackupAppCert34.apk"
+ private const val APP_APK_CERT_4_HISTORY_1_2_4 =
+ "${APK_PATH}CtsPermissionBackupAppCert4History124.apk"
+ private const val APP_LOG_TAG = "PermissionBackupApp"
+ /** The name of the package for backup */
+ private const val ANDROID_PACKAGE = "android"
+ private const val TIMEOUT_MILLIS: Long = 10000
+
+ /**
+ * Make sure that a [Runnable] eventually finishes without throwing an [Exception].
+ *
+ * @param r The [Runnable] to run.
+ */
+ fun eventually(r: Runnable) {
+ val start = System.currentTimeMillis()
+ while (true) {
+ try {
+ r.run()
+ return
+ } catch (e: Throwable) {
+ if (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
+ try {
+ Thread.sleep(100)
+ } catch (ignored: InterruptedException) {
+ throw RuntimeException(e)
+ }
+ } else {
+ throw e
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt b/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt
new file mode 100644
index 00000000000..c77476021d0
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PermissionMemoryFootprintTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts
+
+import android.content.pm.PackageManager
+import android.content.pm.PermissionInfo
+import android.platform.test.annotations.AsbSecurityTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.sts.common.util.StsExtraBusinessLogicTestCase
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PermissionMemoryFootprintTest : StsExtraBusinessLogicTestCase() {
+ companion object {
+ const val MAX_NUM_PERMISSIONS = 32000
+ const val PKG_TREE_NAME = "com.android.cts"
+ val LONG_DESCRIPTION = " ".repeat(MAX_NUM_PERMISSIONS / 10)
+ val SHORT_DESCRIPTION = " ".repeat(MAX_NUM_PERMISSIONS / 100)
+
+ val permInfo = PermissionInfo().apply {
+ labelRes = 1
+ protectionLevel = PermissionInfo.PROTECTION_NORMAL
+ }
+ }
+
+ val packageManager: PackageManager = InstrumentationRegistry.getInstrumentation()
+ .getTargetContext().packageManager!!
+
+ @Throws(SecurityException::class)
+ private fun createOrRemovePermissions(
+ largePerm: Boolean = true,
+ add: Boolean = true,
+ numPerms: Int = MAX_NUM_PERMISSIONS,
+ ): Int {
+ var numPermsCreated = 0
+ for (i in 1..numPerms) {
+ try {
+ permInfo.name = "$PKG_TREE_NAME.$i"
+ permInfo.nonLocalizedDescription = if (largePerm) {
+ LONG_DESCRIPTION
+ } else {
+ SHORT_DESCRIPTION
+ }
+
+ if (add) {
+ packageManager.addPermission(permInfo)
+ } else {
+ packageManager.removePermission(permInfo.name)
+ }
+ } catch (e: SecurityException) {
+ break
+ }
+ numPermsCreated = i
+ }
+ return numPermsCreated
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = [242537498])
+ fun checkAppsCreatingPermissionsAreCapped() {
+ var numCreated = 0
+ try {
+ numCreated = createOrRemovePermissions()
+ Assert.assertNotEquals("Expected at least one permission", numCreated, 0)
+ Assert.assertNotEquals(numCreated, MAX_NUM_PERMISSIONS)
+ } finally {
+ createOrRemovePermissions(add = false, numPerms = numCreated)
+ }
+ }
+
+ @Test
+ @AsbSecurityTest(cveBugId = [242537498])
+ fun checkAppsCantIncreasePermissionSizeAfterCreating() {
+ var numCreatedShort = 0
+ try {
+ numCreatedShort = createOrRemovePermissions(largePerm = false)
+ Assert.assertNotEquals("Expected at least one permission", numCreatedShort, 0)
+ val numCreatedLong = createOrRemovePermissions(numPerms = 1)
+ Assert.assertEquals("Expected to not be able to create a large permission",
+ 0, numCreatedLong)
+ } finally {
+ createOrRemovePermissions(add = false, numPerms = numCreatedShort)
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 307a3e7d01e..9fd10146c1c 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1377,8 +1377,10 @@ public class StagefrightTest extends StsExtraBusinessLogicTestCase {
};
server.start();
String uri = "rtsp://127.0.0.1:8080/cve_2016_3880";
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(new CrashUtils.Config()
- .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT));
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(
+ new CrashUtils.Config()
+ .setSignals(CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT)
+ .appendAbortMessageExcludes("CHECK\\(IsRTSPVersion"));
LooperThread t = new LooperThread(new Runnable() {
@Override
public void run() {
@@ -1809,6 +1811,12 @@ public class StagefrightTest extends StsExtraBusinessLogicTestCase {
before any existing test methods
***********************************************************/
@Test
+ @AsbSecurityTest(cveBugId = 235102508)
+ public void testStagefright_cve_2022_25669() throws Exception {
+ doStagefrightTest(R.raw.cve_2022_25669);
+ }
+
+ @Test
@AsbSecurityTest(cveBugId = 223209306)
public void testStagefright_cve_2022_22085() throws Exception {
doStagefrightTest(R.raw.cve_2022_22085);
diff --git a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
index 73474a1b67e..eeed518b713 100644
--- a/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/WallpaperManagerTest.java
@@ -76,7 +76,9 @@ public class WallpaperManagerTest extends StsExtraBusinessLogicTestCase {
@After
public void tearDown() throws Exception {
- mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+ if (mWallpaperManager != null) {
+ mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+ }
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
diff --git a/tests/tests/security/test-cert-1.pk8 b/tests/tests/security/test-cert-1.pk8
new file mode 100644
index 00000000000..f781c3083e5
--- /dev/null
+++ b/tests/tests/security/test-cert-1.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-1.x509.pem b/tests/tests/security/test-cert-1.x509.pem
new file mode 100644
index 00000000000..06adcfebd3a
--- /dev/null
+++ b/tests/tests/security/test-cert-1.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbDCCARGgAwIBAgIJAMoPtk37ZudyMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTYwMzMxMTQ1ODA2WhcNNDMwODE3MTQ1ODA2WjASMRAwDgYD
+VQQDDAdlYy1wMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl8RPSLLSROQ
+gwesMe4roOkTi3hfrGU20U6izpDStL/hlLUM3I4Wn1SnOpke8Pp2MpglvgeMx4J0
+BwPaRLTX66NQME4wHQYDVR0OBBYEFNQTNWi5WzAVizIgceqMQ/9bBczIMB8GA1Ud
+IwQYMBaAFNQTNWi5WzAVizIgceqMQ/9bBczIMAwGA1UdEwQFMAMBAf8wCgYIKoZI
+zj0EAwIDSQAwRgIhAPUEoIZsrvAp9BcULFy3E1THn/zR1kBhjfyk8Z4W23jWAiEA
++O6kgpeZwGytCMbT0tLsBeBXQVTnR+oP27gELLZVqt0=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-2.pk8 b/tests/tests/security/test-cert-2.pk8
new file mode 100644
index 00000000000..5e73f27847d
--- /dev/null
+++ b/tests/tests/security/test-cert-2.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-2.x509.pem b/tests/tests/security/test-cert-2.x509.pem
new file mode 100644
index 00000000000..f8e5e65b628
--- /dev/null
+++ b/tests/tests/security/test-cert-2.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbTCCAROgAwIBAgIJAIhVvR3SsrIlMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTgwNzEzMTc0MTUxWhcNMjgwNzEwMTc0MTUxWjAUMRIwEAYD
+VQQDDAllYy1wMjU2XzIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQdTMoEcq2X
+7jzs7w2pPWK0UMZ4gzOzbnVTzen3SrXfALu6a6lQ5oRh1wu8JxtiFR2tLeK/YgPN
+IHaAHHqdRCLho1AwTjAdBgNVHQ4EFgQUeZHZKwII/ESL9QbU78n/9CjLXl8wHwYD
+VR0jBBgwFoAU1BM1aLlbMBWLMiBx6oxD/1sFzMgwDAYDVR0TBAUwAwEB/zAKBggq
+hkjOPQQDAgNIADBFAiAnaauxtJ/C9TR5xK6SpmMdq/1SLJrLC7orQ+vrmcYwEQIh
+ANJg+x0fF2z5t/pgCYv9JDGfSQWj5f2hAKb+Giqxn/Ce
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-3.pk8 b/tests/tests/security/test-cert-3.pk8
new file mode 100644
index 00000000000..d7309dd3f02
--- /dev/null
+++ b/tests/tests/security/test-cert-3.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-3.x509.pem b/tests/tests/security/test-cert-3.x509.pem
new file mode 100644
index 00000000000..c028ff7d1e2
--- /dev/null
+++ b/tests/tests/security/test-cert-3.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbjCCARWgAwIBAgIJAIOU9crRaomnMAoGCCqGSM49BAMCMBQxEjAQBgNVBAMM
+CWVjLXAyNTZfMjAeFw0xODA3MTQwMDA1MjZaFw0yODA3MTEwMDA1MjZaMBQxEjAQ
+BgNVBAMMCWVjLXAyNTZfMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPMeYkMO
+nbb8WSjZdfxOR0GbrPyy4HyJKZ5s1+NE3SGt/TCNWMtJoaKj/srM7qSGIGnzC+Fk
+O8wlUEDYCJ37N0OjUDBOMB0GA1UdDgQWBBRvjQgosT769Xf8hrDpn6PlS8vP8DAf
+BgNVHSMEGDAWgBR5kdkrAgj8RIv1BtTvyf/0KMteXzAMBgNVHRMEBTADAQH/MAoG
+CCqGSM49BAMCA0cAMEQCICVr2qJ4TCc+TMKRpZWkZ3ne6d6QRNyferggMJVn35/p
+AiAaStjGmJG1qMR0NP6VQO0fSXm1+tNIPz+gTVZ3NVpXng==
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-4.pk8 b/tests/tests/security/test-cert-4.pk8
new file mode 100644
index 00000000000..3675d50c54f
--- /dev/null
+++ b/tests/tests/security/test-cert-4.pk8
Binary files differ
diff --git a/tests/tests/security/test-cert-4.x509.pem b/tests/tests/security/test-cert-4.x509.pem
new file mode 100644
index 00000000000..4060400cb6c
--- /dev/null
+++ b/tests/tests/security/test-cert-4.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBezCCASCgAwIBAgIUbIy4qBhDPB5kMfsW+zrg+1rWCqcwCgYIKoZIzj0EAwIw
+FDESMBAGA1UEAwwJZWMtcDI1Nl8zMB4XDTIwMDUxMzE5MTUyOFoXDTMwMDUxMTE5
+MTUyOFowFDESMBAGA1UEAwwJZWMtcDI1Nl80MFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAE20pgAx55rUnLdZAH1oVdRGm5HIurBlQ08vupca3n5NGVmaD2e15wjP2n
+VD5WMMN2nTfgk2QNfHaKFRRM0OXc9KNQME4wHQYDVR0OBBYEFG54lwMyVUM2tu6J
+JOqnAjDjk/Z4MB8GA1UdIwQYMBaAFG+NCCixPvr1d/yGsOmfo+VLy8/wMAwGA1Ud
+EwQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAM54bnnsdUdEYILpyvkQYU/4B1j5
+gZ+w8UhpUGer4PzUAiEApIgeMy3ewhFq0rWc+JHQ8zH/fifne3xiBseYjZtTkzA=
+-----END CERTIFICATE-----
diff --git a/tests/tests/security/test-cert-with-1-2-4-in-rotation-history b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
new file mode 100644
index 00000000000..7326e46f85b
--- /dev/null
+++ b/tests/tests/security/test-cert-with-1-2-4-in-rotation-history
Binary files differ
diff --git a/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
new file mode 100644
index 00000000000..2b75d8c846a
--- /dev/null
+++ b/tests/tests/security/testdata/permissionbackuptestapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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.permissionbackup" >
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+ <application
+ android:label="Android Permission Backup CTS App">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/tests/webkit/Android.bp b/tests/tests/webkit/Android.bp
index d8175dd4423..a046dae6fe3 100644
--- a/tests/tests/webkit/Android.bp
+++ b/tests/tests/webkit/Android.bp
@@ -25,6 +25,7 @@ android_test {
"android.test.base",
],
static_libs: [
+ "androidx.test.core",
"compatibility-device-util-axt",
"ctsdeviceutillegacy-axt",
"ctstestserver",
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index abe44ea1155..7ca3f468353 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -19,6 +19,7 @@ package android.webkit.cts;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.*;
import android.content.ContentResolver;
import android.content.Context;
@@ -49,18 +50,13 @@ import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.print.PrintDocumentInfo;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.View;
import android.view.ViewGroup;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextSelection;
-import android.webkit.ConsoleMessage;
import android.webkit.CookieSyncManager;
import android.webkit.DownloadListener;
import android.webkit.JavascriptInterface;
@@ -81,47 +77,53 @@ import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
import android.webkit.cts.WebViewSyncLoader.WaitForProgressClient;
import android.widget.LinearLayout;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.FlakyTest;
import com.android.compatibility.common.util.NullWebViewUtils;
import com.android.compatibility.common.util.PollingCheck;
+
import com.google.common.util.concurrent.SettableFuture;
-import java.io.ByteArrayInputStream;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpRequest;
+import org.apache.http.util.EncodingUtils;
+import org.apache.http.util.EntityUtils;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-
import java.net.MalformedURLException;
import java.net.URL;
-
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpRequest;
-import org.apache.http.util.EncodingUtils;
-import org.apache.http.util.EntityUtils;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
@AppModeFull
-public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
+@RunWith(AndroidJUnit4.class)
+public class WebViewTest {
private static final int INITIAL_PROGRESS = 100;
private static final String X_REQUESTED_WITH = "X-Requested-With";
private static final String PRINTER_TEST_FILE = "print.pdf";
@@ -132,59 +134,62 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
private static final String SIMPLE_HTML = "<html><body>simple html</body></html>";
/**
- * This is the minimum number of milliseconds to wait for scrolling to
- * start. If no scrolling has started before this timeout then it is
- * assumed that no scrolling will happen.
+ * This is the minimum number of milliseconds to wait for scrolling to start. If no scrolling
+ * has started before this timeout then it is assumed that no scrolling will happen.
*/
private static final long MIN_SCROLL_WAIT_MS = 1000;
/**
- * This is the minimum number of milliseconds to wait for findAll to
- * find all the matches. If matches are not found, the Listener would
- * call findAll again until it times out.
+ * This is the minimum number of milliseconds to wait for findAll to find all the matches. If
+ * matches are not found, the Listener would call findAll again until it times out.
*/
private static final long MIN_FIND_WAIT_MS = 3000;
/**
- * Once scrolling has started, this is the interval that scrolling
- * is checked to see if there is a change. If no scrolling change
- * has happened in the given time then it is assumed that scrolling
- * has stopped.
+ * Once scrolling has started, this is the interval that scrolling is checked to see if there is
+ * a change. If no scrolling change has happened in the given time then it is assumed that
+ * scrolling has stopped.
*/
private static final long SCROLL_WAIT_INTERVAL_MS = 200;
+ @Rule
+ public ActivityScenarioRule mActivityScenarioRule =
+ new ActivityScenarioRule(WebViewCtsActivity.class);
+
+ private ActivityScenario mScenario;
+ private WebViewCtsActivity mActivity;
private WebView mWebView;
private CtsTestServer mWebServer;
private WebViewOnUiThread mOnUiThread;
private WebIconDatabase mIconDb;
- public WebViewTest() {
- super("com.android.cts.webkit", WebViewCtsActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- final WebViewCtsActivity activity = getActivity();
- mWebView = activity.getWebView();
+ @Before
+ public void setUp() throws Exception {
+ mScenario = mActivityScenarioRule.getScenario();
+ mScenario.onActivity(
+ activity -> {
+ mActivity = (WebViewCtsActivity) activity;
+ mWebView = mActivity.getWebView();
+ });
if (mWebView != null) {
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
- protected boolean check() {
- return activity.hasWindowFocus();
+ protected boolean check() {
+ return mActivity.hasWindowFocus();
}
}.run();
- File f = activity.getFileStreamPath("snapshot");
+ File f = mActivity.getFileStreamPath("snapshot");
if (f.exists()) {
f.delete();
}
mOnUiThread = new WebViewOnUiThread(mWebView);
}
+ Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void cleanup() throws Exception {
if (mOnUiThread != null) {
mOnUiThread.cleanUp();
}
@@ -196,171 +201,176 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mIconDb.close();
mIconDb = null;
}
- super.tearDown();
+ mActivity = null;
}
private void startWebServer(boolean secure) throws Exception {
assertNull(mWebServer);
- mWebServer = new CtsTestServer(getActivity(), secure);
+ mWebServer = new CtsTestServer(mActivity, secure);
}
private void stopWebServer() throws Exception {
assertNotNull(mWebServer);
ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
- ThreadPolicy tmpPolicy = new ThreadPolicy.Builder(oldPolicy)
- .permitNetwork()
- .build();
+ ThreadPolicy tmpPolicy = new ThreadPolicy.Builder(oldPolicy).permitNetwork().build();
StrictMode.setThreadPolicy(tmpPolicy);
mWebServer.shutdown();
mWebServer = null;
StrictMode.setThreadPolicy(oldPolicy);
}
- @UiThreadTest
+ @Test
public void testConstructor() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- WebView webView = new WebView(getActivity());
- webView.destroy();
- webView = new WebView(getActivity(), null);
- webView.destroy();
- webView = new WebView(getActivity(), null, 0);
- webView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ WebView webView = new WebView(mActivity);
+ webView.destroy();
+ webView = new WebView(mActivity, null);
+ webView.destroy();
+ webView = new WebView(mActivity, null, 0);
+ webView.destroy();
+ });
}
- @UiThreadTest
+ @Test
public void testCreatingWebViewWithDeviceEncrpytionFails() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- Context deviceEncryptedContext = getActivity().createDeviceProtectedStorageContext();
- try {
- new WebView(deviceEncryptedContext);
- fail("WebView should have thrown exception when creating with a device " +
- "protected storage context");
- } catch (IllegalArgumentException e) {}
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ Context deviceEncryptedContext =
+ mActivity.createDeviceProtectedStorageContext();
+ try {
+ new WebView(deviceEncryptedContext);
+ fail(
+ "WebView should have thrown exception when creating with a device "
+ + "protected storage context");
+ } catch (IllegalArgumentException e) {
+ }
+ });
}
- @UiThreadTest
+ @Test
public void testCreatingWebViewWithMultipleEncryptionContext() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- // Credential encrpytion is the default. Create one here for the sake of clarity.
- Context credentialEncryptedContext = getActivity().createCredentialProtectedStorageContext();
- Context deviceEncryptedContext = getActivity().createDeviceProtectedStorageContext();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ // Credential encryption is the default. Create one here for the sake of
+ // clarity.
+ Context credentialEncryptedContext =
+ mActivity.createCredentialProtectedStorageContext();
+ Context deviceEncryptedContext =
+ mActivity.createDeviceProtectedStorageContext();
+
+ // No exception should be thrown with credential encryption context.
+ WebView webView = new WebView(credentialEncryptedContext);
+ webView.destroy();
- // No exception should be thrown with credential encryption context.
- WebView webView = new WebView(credentialEncryptedContext);
- webView.destroy();
-
- try {
- new WebView(deviceEncryptedContext);
- fail("WebView should have thrown exception when creating with a device " +
- "protected storage context");
- } catch (IllegalArgumentException e) {}
+ try {
+ new WebView(deviceEncryptedContext);
+ fail(
+ "WebView should have thrown exception when creating with a device "
+ + "protected storage context");
+ } catch (IllegalArgumentException e) {
+ }
+ });
}
- @UiThreadTest
+ @Test
public void testCreatingWebViewCreatesCookieSyncManager() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- WebView webView = new WebView(getActivity());
- assertNotNull(CookieSyncManager.getInstance());
- webView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ WebView webView = new WebView(mActivity);
+ assertNotNull(CookieSyncManager.getInstance());
+ webView.destroy();
+ });
}
+ @Test
// Static methods should be safe to call on non-UI threads
public void testFindAddress() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
/*
* Info about USPS
* http://en.wikipedia.org/wiki/Postal_address#United_States
* http://www.usps.com/
*/
// full address
- assertEquals("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92826",
+ assertEquals(
+ "455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92826",
WebView.findAddress("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92826"));
// Zipcode is optional.
- assertEquals("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA",
+ assertEquals(
+ "455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA",
WebView.findAddress("455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA"));
// not an address
assertNull(WebView.findAddress("This is not an address: no town, no state, no zip."));
// would be an address, except for numbers that are not ASCII
- assertNull(WebView.findAddress(
- "80\uD835\uDFEF \uD835\uDFEF\uD835\uDFEFth Avenue Sunnyvale, CA 94089"));
+ assertNull(
+ WebView.findAddress(
+ "80\uD835\uDFEF \uD835\uDFEF\uD835\uDFEFth Avenue Sunnyvale, CA 94089"));
}
- @UiThreadTest
+ @Test
public void testScrollBarOverlay() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- // These functions have no effect; just verify they don't crash
- mWebView.setHorizontalScrollbarOverlay(true);
- mWebView.setVerticalScrollbarOverlay(false);
-
- assertTrue(mWebView.overlayHorizontalScrollbar());
- assertFalse(mWebView.overlayVerticalScrollbar());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ // These functions have no effect; just verify they don't crash
+ mWebView.setHorizontalScrollbarOverlay(true);
+ mWebView.setVerticalScrollbarOverlay(false);
+
+ assertTrue(mWebView.overlayHorizontalScrollbar());
+ assertFalse(mWebView.overlayVerticalScrollbar());
+ });
}
+ @Test
@Presubmit
- @UiThreadTest
public void testLoadUrl() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- assertNull(mWebView.getUrl());
- assertNull(mWebView.getOriginalUrl());
- assertEquals(INITIAL_PROGRESS, mWebView.getProgress());
-
startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
- assertEquals(100, mWebView.getProgress());
- assertEquals(url, mWebView.getUrl());
- assertEquals(url, mWebView.getOriginalUrl());
- assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mWebView.getTitle());
-
- // verify that the request also includes X-Requested-With header
- HttpRequest request = mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
- Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
- assertEquals(1, matchingHeaders.length);
- Header header = matchingHeaders[0];
- assertEquals(mWebView.getContext().getApplicationInfo().packageName, header.getValue());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ assertNull(mWebView.getUrl());
+ assertNull(mWebView.getOriginalUrl());
+ assertEquals(INITIAL_PROGRESS, mWebView.getProgress());
+
+ String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ assertEquals(100, mWebView.getProgress());
+ assertEquals(url, mWebView.getUrl());
+ assertEquals(url, mWebView.getOriginalUrl());
+ assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mWebView.getTitle());
+
+ // verify that the request also includes X-Requested-With header
+ HttpRequest request =
+ mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
+ Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
+ assertEquals(1, matchingHeaders.length);
+
+ Header header = matchingHeaders[0];
+ assertEquals(
+ mWebView.getContext().getApplicationInfo().packageName,
+ header.getValue());
+ });
}
- @UiThreadTest
+ @Test
public void testPostUrlWithNonNetworkUrl() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final String nonNetworkUrl = "file:///android_asset/" + TestHtmlConstants.HELLO_WORLD_URL;
mOnUiThread.postUrlAndWaitForCompletion(nonNetworkUrl, new byte[1]);
- assertEquals("Non-network URL should have loaded", TestHtmlConstants.HELLO_WORLD_TITLE,
- mWebView.getTitle());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ assertEquals(
+ "Non-network URL should have loaded",
+ TestHtmlConstants.HELLO_WORLD_TITLE,
+ mWebView.getTitle());
+ });
}
- @UiThreadTest
+ @Test
public void testPostUrlWithNetworkUrl() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
startWebServer(false);
+
final String networkUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
final String postDataString = "username=my_username&password=my_password";
final byte[] postData = EncodingUtils.getBytes(postDataString, "BASE64");
@@ -368,83 +378,84 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.postUrlAndWaitForCompletion(networkUrl, postData);
HttpRequest request = mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
- assertEquals("The last request should be POST", request.getRequestLine().getMethod(),
- "POST");
+ assertEquals(
+ "The last request should be POST", request.getRequestLine().getMethod(), "POST");
- assertTrue("The last request should have a request body",
+ assertTrue(
+ "The last request should have a request body",
request instanceof HttpEntityEnclosingRequest);
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
String entityString = EntityUtils.toString(entity);
assertEquals(entityString, postDataString);
}
- @UiThreadTest
+ @Test
public void testLoadUrlDoesNotStripParamsWhenLoadingContentUrls() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- Uri.Builder uriBuilder = new Uri.Builder().scheme(
- ContentResolver.SCHEME_CONTENT).authority(MockContentProvider.AUTHORITY);
- uriBuilder.appendPath("foo.html").appendQueryParameter("param","bar");
- String url = uriBuilder.build().toString();
- mOnUiThread.loadUrlAndWaitForCompletion(url);
- // verify the parameter is not stripped.
- Uri uri = Uri.parse(mWebView.getTitle());
- assertEquals("bar", uri.getQueryParameter("param"));
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ Uri.Builder uriBuilder =
+ new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(MockContentProvider.AUTHORITY);
+ uriBuilder.appendPath("foo.html").appendQueryParameter("param", "bar");
+ String url = uriBuilder.build().toString();
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ // verify the parameter is not stripped.
+ Uri uri = Uri.parse(mWebView.getTitle());
+ assertEquals("bar", uri.getQueryParameter("param"));
+ });
}
- @UiThreadTest
+ @Test
public void testAppInjectedXRequestedWithHeaderIsNotOverwritten() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- HashMap<String, String> map = new HashMap<String, String>();
- final String requester = "foo";
- map.put(X_REQUESTED_WITH, requester);
- mOnUiThread.loadUrlAndWaitForCompletion(url, map);
- // verify that the request also includes X-Requested-With header
- // but is not overwritten by the webview
- HttpRequest request = mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
- Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
- assertEquals(1, matchingHeaders.length);
-
- Header header = matchingHeaders[0];
- assertEquals(requester, header.getValue());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ HashMap<String, String> map = new HashMap<String, String>();
+ final String requester = "foo";
+ map.put(X_REQUESTED_WITH, requester);
+ mOnUiThread.loadUrlAndWaitForCompletion(url, map);
+
+ // verify that the request also includes X-Requested-With header
+ // but is not overwritten by the webview
+ HttpRequest request =
+ mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
+ Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
+ assertEquals(1, matchingHeaders.length);
+
+ Header header = matchingHeaders[0];
+ assertEquals(requester, header.getValue());
+ });
}
- @UiThreadTest
+ @Test
public void testAppCanInjectHeadersViaImmutableMap() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- HashMap<String, String> map = new HashMap<String, String>();
- final String requester = "foo";
- map.put(X_REQUESTED_WITH, requester);
- mOnUiThread.loadUrlAndWaitForCompletion(url, Collections.unmodifiableMap(map));
-
- // verify that the request also includes X-Requested-With header
- // but is not overwritten by the webview
- HttpRequest request = mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
- Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
- assertEquals(1, matchingHeaders.length);
- Header header = matchingHeaders[0];
- assertEquals(requester, header.getValue());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ HashMap<String, String> map = new HashMap<String, String>();
+ final String requester = "foo";
+ map.put(X_REQUESTED_WITH, requester);
+ mOnUiThread.loadUrlAndWaitForCompletion(url, Collections.unmodifiableMap(map));
+
+ // verify that the request also includes X-Requested-With header
+ // but is not overwritten by the webview
+ HttpRequest request =
+ mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
+ Header[] matchingHeaders = request.getHeaders(X_REQUESTED_WITH);
+ assertEquals(1, matchingHeaders.length);
+
+ Header header = matchingHeaders[0];
+ assertEquals(requester, header.getValue());
+ });
}
+ @Test
public void testCanInjectHeaders() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final String X_FOO = "X-foo";
final String X_FOO_VALUE = "test";
@@ -458,7 +469,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.loadUrlAndWaitForCompletion(url, map);
HttpRequest request = mWebServer.getLastRequest(TestHtmlConstants.HELLO_WORLD_URL);
- for (Map.Entry<String,String> value : map.entrySet()) {
+ for (Map.Entry<String, String> value : map.entrySet()) {
String header = value.getKey();
Header[] matchingHeaders = request.getHeaders(header);
assertEquals("header " + header + " not found", 1, matchingHeaders.length);
@@ -466,49 +477,47 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
}
+ @Test
@SuppressWarnings("deprecation")
- @UiThreadTest
public void testGetVisibleTitleHeight() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
- assertEquals(0, mWebView.getVisibleTitleHeight());
+
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ assertEquals(0, mWebView.getVisibleTitleHeight());
+ });
}
- @UiThreadTest
+ @Test
public void testGetOriginalUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
startWebServer(false);
- final String finalUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- final String redirectUrl =
- mWebServer.getRedirectingAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
-
- assertNull(mWebView.getUrl());
- assertNull(mWebView.getOriginalUrl());
-
- // By default, WebView sends an intent to ask the system to
- // handle loading a new URL. We set a WebViewClient as
- // WebViewClient.shouldOverrideUrlLoading() returns false, so
- // the WebView will load the new URL.
- mWebView.setWebViewClient(new WaitForLoadedClient(mOnUiThread));
- mOnUiThread.loadUrlAndWaitForCompletion(redirectUrl);
- assertEquals(finalUrl, mWebView.getUrl());
- assertEquals(redirectUrl, mWebView.getOriginalUrl());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ final String finalUrl =
+ mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ final String redirectUrl =
+ mWebServer.getRedirectingAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+
+ assertNull(mWebView.getUrl());
+ assertNull(mWebView.getOriginalUrl());
+
+ // By default, WebView sends an intent to ask the system to
+ // handle loading a new URL. We set a WebViewClient as
+ // WebViewClient.shouldOverrideUrlLoading() returns false, so
+ // the WebView will load the new URL.
+ mWebView.setWebViewClient(new WaitForLoadedClient(mOnUiThread));
+ mOnUiThread.loadUrlAndWaitForCompletion(redirectUrl);
+
+ assertEquals(finalUrl, mWebView.getUrl());
+ assertEquals(redirectUrl, mWebView.getOriginalUrl());
+ });
}
+ @Test
public void testStopLoading() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
assertEquals(INITIAL_PROGRESS, mOnUiThread.getProgress());
startWebServer(false);
@@ -522,6 +531,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mPageLoaded = true;
notify();
}
+
public synchronized boolean getPageLoaded() {
return mPageLoaded;
}
@@ -542,61 +552,58 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertFalse(jsInterface.getPageLoaded());
}
- @UiThreadTest
+ @Test
public void testGoBackAndForward() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- assertGoBackOrForwardBySteps(false, -1);
- assertGoBackOrForwardBySteps(false, 1);
-
startWebServer(false);
- String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
- String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
- String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
-
- mOnUiThread.loadUrlAndWaitForCompletion(url1);
- pollingCheckWebBackForwardList(url1, 0, 1);
- assertGoBackOrForwardBySteps(false, -1);
- assertGoBackOrForwardBySteps(false, 1);
-
- mOnUiThread.loadUrlAndWaitForCompletion(url2);
- pollingCheckWebBackForwardList(url2, 1, 2);
- assertGoBackOrForwardBySteps(true, -1);
- assertGoBackOrForwardBySteps(false, 1);
- mOnUiThread.loadUrlAndWaitForCompletion(url3);
- pollingCheckWebBackForwardList(url3, 2, 3);
- assertGoBackOrForwardBySteps(true, -2);
- assertGoBackOrForwardBySteps(false, 1);
-
- mWebView.goBack();
- pollingCheckWebBackForwardList(url2, 1, 3);
- assertGoBackOrForwardBySteps(true, -1);
- assertGoBackOrForwardBySteps(true, 1);
-
- mWebView.goForward();
- pollingCheckWebBackForwardList(url3, 2, 3);
- assertGoBackOrForwardBySteps(true, -2);
- assertGoBackOrForwardBySteps(false, 1);
-
- mWebView.goBackOrForward(-2);
- pollingCheckWebBackForwardList(url1, 0, 3);
- assertGoBackOrForwardBySteps(false, -1);
- assertGoBackOrForwardBySteps(true, 2);
-
- mWebView.goBackOrForward(2);
- pollingCheckWebBackForwardList(url3, 2, 3);
- assertGoBackOrForwardBySteps(true, -2);
- assertGoBackOrForwardBySteps(false, 1);
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ assertGoBackOrForwardBySteps(false, -1);
+ assertGoBackOrForwardBySteps(false, 1);
+
+ String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
+ String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
+ String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
+
+ mOnUiThread.loadUrlAndWaitForCompletion(url1);
+ pollingCheckWebBackForwardList(url1, 0, 1);
+ assertGoBackOrForwardBySteps(false, -1);
+ assertGoBackOrForwardBySteps(false, 1);
+
+ mOnUiThread.loadUrlAndWaitForCompletion(url2);
+ pollingCheckWebBackForwardList(url2, 1, 2);
+ assertGoBackOrForwardBySteps(true, -1);
+ assertGoBackOrForwardBySteps(false, 1);
+
+ mOnUiThread.loadUrlAndWaitForCompletion(url3);
+ pollingCheckWebBackForwardList(url3, 2, 3);
+ assertGoBackOrForwardBySteps(true, -2);
+ assertGoBackOrForwardBySteps(false, 1);
+
+ mWebView.goBack();
+ pollingCheckWebBackForwardList(url2, 1, 3);
+ assertGoBackOrForwardBySteps(true, -1);
+ assertGoBackOrForwardBySteps(true, 1);
+
+ mWebView.goForward();
+ pollingCheckWebBackForwardList(url3, 2, 3);
+ assertGoBackOrForwardBySteps(true, -2);
+ assertGoBackOrForwardBySteps(false, 1);
+
+ mWebView.goBackOrForward(-2);
+ pollingCheckWebBackForwardList(url1, 0, 3);
+ assertGoBackOrForwardBySteps(false, -1);
+ assertGoBackOrForwardBySteps(true, 2);
+
+ mWebView.goBackOrForward(2);
+ pollingCheckWebBackForwardList(url3, 2, 3);
+ assertGoBackOrForwardBySteps(true, -2);
+ assertGoBackOrForwardBySteps(false, 1);
+ });
}
+ @Test
public void testAddJavascriptInterface() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
@@ -641,77 +648,66 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// Verify that only methods annotated with @JavascriptInterface are exposed
// on the JavaScript interface object.
- assertEquals("\"function\"",
+ assertEquals(
+ "\"function\"",
mOnUiThread.evaluateJavascriptSync("typeof interface.provideResult"));
- assertEquals("\"undefined\"",
+ assertEquals(
+ "\"undefined\"",
mOnUiThread.evaluateJavascriptSync("typeof interface.wasProvideResultCalled"));
- assertEquals("\"undefined\"",
- mOnUiThread.evaluateJavascriptSync("typeof interface.getClass"));
+ assertEquals(
+ "\"undefined\"", mOnUiThread.evaluateJavascriptSync("typeof interface.getClass"));
}
+ @Test
public void testAddJavascriptInterfaceNullObject() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.getSettings().setJavaScriptEnabled(true);
- String setTitleToPropertyTypeHtml = "<html><head></head>" +
- "<body onload=\"document.title = typeof window.injectedObject;\"></body></html>";
+ String setTitleToPropertyTypeHtml =
+ "<html><head></head><body onload=\"document.title = typeof"
+ + " window.injectedObject;\"></body></html>";
// Test that the property is initially undefined.
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("undefined", mOnUiThread.getTitle());
// Test that adding a null object has no effect.
mOnUiThread.addJavascriptInterface(null, "injectedObject");
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("undefined", mOnUiThread.getTitle());
// Test that adding an object gives an object type.
final Object obj = new Object();
mOnUiThread.addJavascriptInterface(obj, "injectedObject");
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("object", mOnUiThread.getTitle());
// Test that trying to replace with a null object has no effect.
mOnUiThread.addJavascriptInterface(null, "injectedObject");
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("object", mOnUiThread.getTitle());
}
+ @Test
public void testRemoveJavascriptInterface() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.getSettings().setJavaScriptEnabled(true);
- String setTitleToPropertyTypeHtml = "<html><head></head>" +
- "<body onload=\"document.title = typeof window.injectedObject;\"></body></html>";
+ String setTitleToPropertyTypeHtml =
+ "<html><head></head><body onload=\"document.title = typeof"
+ + " window.injectedObject;\"></body></html>";
// Test that adding an object gives an object type.
mOnUiThread.addJavascriptInterface(new Object(), "injectedObject");
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("object", mOnUiThread.getTitle());
// Test that reloading the page after removing the object leaves the property undefined.
mOnUiThread.removeJavascriptInterface("injectedObject");
- mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml,
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(setTitleToPropertyTypeHtml, "text/html", null);
assertEquals("undefined", mOnUiThread.getTitle());
}
+ @Test
public void testUseRemovedJavascriptInterface() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
class RemovedObject {
@Override
@JavascriptInterface
@@ -735,6 +731,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mIsResultAvailable = true;
notify();
}
+
public synchronized String getResult() {
while (!mIsResultAvailable) {
try {
@@ -752,30 +749,31 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.addJavascriptInterface(new RemovedObject(), "removedObject");
mOnUiThread.addJavascriptInterface(resultObject, "resultObject");
- mOnUiThread.loadDataAndWaitForCompletion("<html><head></head>" +
- "<body onload=\"window.removedObject.remove();" +
- "resultObject.setResult(removedObject.toString());\"></body></html>",
- "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><head></head>"
+ + "<body onload=\"window.removedObject.remove();"
+ + "resultObject.setResult(removedObject.toString());\"></body></html>",
+ "text/html",
+ null);
assertEquals("removedObject", resultObject.getResult());
}
+ @Test
public void testAddJavascriptInterfaceExceptions() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
WebSettings settings = mOnUiThread.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
- final AtomicBoolean mJsInterfaceWasCalled = new AtomicBoolean(false) {
- @JavascriptInterface
- public synchronized void call() {
- set(true);
- // The main purpose of this test is to ensure an exception here does not
- // crash the implementation.
- throw new RuntimeException("Javascript Interface exception");
- }
- };
+ final AtomicBoolean mJsInterfaceWasCalled =
+ new AtomicBoolean(false) {
+ @JavascriptInterface
+ public synchronized void call() {
+ set(true);
+ // The main purpose of this test is to ensure an exception here does not
+ // crash the implementation.
+ throw new RuntimeException("Javascript Interface exception");
+ }
+ };
mOnUiThread.addJavascriptInterface(mJsInterfaceWasCalled, "interface");
@@ -783,16 +781,15 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertFalse(mJsInterfaceWasCalled.get());
- assertEquals("\"pass\"", mOnUiThread.evaluateJavascriptSync(
- "try {interface.call(); 'fail'; } catch (exception) { 'pass'; } "));
+ assertEquals(
+ "\"pass\"",
+ mOnUiThread.evaluateJavascriptSync(
+ "try {interface.call(); 'fail'; } catch (exception) { 'pass'; } "));
assertTrue(mJsInterfaceWasCalled.get());
}
+ @Test
public void testJavascriptInterfaceCustomPropertiesClearedOnReload() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.addJavascriptInterface(new Object(), "interface");
@@ -807,12 +804,9 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertEquals("false", mOnUiThread.evaluateJavascriptSync("'custom_property' in interface"));
}
+ @Test
@FlakyTest(bugId = 171702662)
public void testJavascriptInterfaceForClientPopup() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
mOnUiThread.getSettings().setSupportMultipleWindows(true);
@@ -831,31 +825,40 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
childOnUiThread.addJavascriptInterface(obj, "interface");
final SettableFuture<Void> onCreateWindowFuture = SettableFuture.create();
- mOnUiThread.setWebChromeClient(new WebViewSyncLoader.WaitForProgressClient(mOnUiThread) {
- @Override
- public boolean onCreateWindow(
- WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
- getActivity().addContentView(childWebView, new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
- transport.setWebView(childWebView);
- resultMsg.sendToTarget();
- onCreateWindowFuture.set(null);
- return true;
- }
- });
+ mOnUiThread.setWebChromeClient(
+ new WebViewSyncLoader.WaitForProgressClient(mOnUiThread) {
+ @Override
+ public boolean onCreateWindow(
+ WebView view,
+ boolean isDialog,
+ boolean isUserGesture,
+ Message resultMsg) {
+ mActivity.addContentView(
+ childWebView,
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ WebView.WebViewTransport transport =
+ (WebView.WebViewTransport) resultMsg.obj;
+ transport.setWebView(childWebView);
+ resultMsg.sendToTarget();
+ onCreateWindowFuture.set(null);
+ return true;
+ }
+ });
startWebServer(false);
- mOnUiThread.loadUrlAndWaitForCompletion(mWebServer.
- getAssetUrl(TestHtmlConstants.POPUP_URL));
+ mOnUiThread.loadUrlAndWaitForCompletion(
+ mWebServer.getAssetUrl(TestHtmlConstants.POPUP_URL));
WebkitUtils.waitForFuture(onCreateWindowFuture);
childOnUiThread.loadUrlAndWaitForCompletion("about:blank");
assertEquals("true", childOnUiThread.evaluateJavascriptSync("'interface' in window"));
- assertEquals("The injected object should be functional", "42",
+ assertEquals(
+ "The injected object should be functional",
+ "42",
childOnUiThread.evaluateJavascriptSync("interface.test()"));
}
@@ -871,17 +874,17 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
}
- private Picture waitForPictureToHaveColor(int color,
- final TestPictureListener listener) throws Throwable {
+ private Picture waitForPictureToHaveColor(int color, final TestPictureListener listener)
+ throws Throwable {
final int MAX_ON_NEW_PICTURE_ITERATIONS = 5;
final AtomicReference<Picture> pictureRef = new AtomicReference<Picture>();
for (int i = 0; i < MAX_ON_NEW_PICTURE_ITERATIONS; i++) {
final int oldCallCount = listener.callCount;
- WebkitUtils.onMainThreadSync(() -> {
- pictureRef.set(mWebView.capturePicture());
- });
- if (isPictureFilledWithColor(pictureRef.get(), color))
- break;
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ pictureRef.set(mWebView.capturePicture());
+ });
+ if (isPictureFilledWithColor(pictureRef.get(), color)) break;
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -892,10 +895,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
return pictureRef.get();
}
+ @Test
public void testCapturePicture() throws Exception, Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final TestPictureListener listener = new TestPictureListener();
startWebServer(false);
@@ -906,20 +907,20 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// The default background color is white.
Picture oldPicture = waitForPictureToHaveColor(Color.WHITE, listener);
- WebkitUtils.onMainThread(() -> {
- mWebView.setBackgroundColor(Color.CYAN);
- });
+ WebkitUtils.onMainThread(
+ () -> {
+ mWebView.setBackgroundColor(Color.CYAN);
+ });
mOnUiThread.reloadAndWaitForCompletion();
waitForPictureToHaveColor(Color.CYAN, listener);
- assertTrue("The content of the previously captured picture should not update automatically",
+ assertTrue(
+ "The content of the previously captured picture should not update automatically",
isPictureFilledWithColor(oldPicture, Color.WHITE));
}
+ @Test
public void testSetPictureListener() throws Exception, Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final class MyPictureListener implements PictureListener {
public int callCount;
public WebView webView;
@@ -961,149 +962,145 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
- @UiThreadTest
+ @Test
public void testAccessHttpAuthUsernamePassword() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- try {
- WebViewDatabase.getInstance(getActivity()).clearHttpAuthUsernamePassword();
-
- String host = "http://localhost:8080";
- String realm = "testrealm";
- String userName = "user";
- String password = "password";
-
- String[] result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNull(result);
-
- mWebView.setHttpAuthUsernamePassword(host, realm, userName, password);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertEquals(password, result[1]);
-
- String newPassword = "newpassword";
- mWebView.setHttpAuthUsernamePassword(host, realm, userName, newPassword);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertEquals(newPassword, result[1]);
-
- String newUserName = "newuser";
- mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(newUserName, result[0]);
- assertEquals(newPassword, result[1]);
-
- // the user is set to null, can not change any thing in the future
- mWebView.setHttpAuthUsernamePassword(host, realm, null, password);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertNull(result[0]);
- assertEquals(password, result[1]);
-
- mWebView.setHttpAuthUsernamePassword(host, realm, userName, null);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertNull(result[1]);
-
- mWebView.setHttpAuthUsernamePassword(host, realm, null, null);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertNull(result[0]);
- assertNull(result[1]);
-
- mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
- result = mWebView.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(newUserName, result[0]);
- assertEquals(newPassword, result[1]);
- } finally {
- WebViewDatabase.getInstance(getActivity()).clearHttpAuthUsernamePassword();
- }
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ try {
+ WebViewDatabase.getInstance(mActivity).clearHttpAuthUsernamePassword();
+
+ String host = "http://localhost:8080";
+ String realm = "testrealm";
+ String userName = "user";
+ String password = "password";
+
+ String[] result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNull(result);
+
+ mWebView.setHttpAuthUsernamePassword(host, realm, userName, password);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertEquals(password, result[1]);
+
+ String newPassword = "newpassword";
+ mWebView.setHttpAuthUsernamePassword(host, realm, userName, newPassword);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertEquals(newPassword, result[1]);
+
+ String newUserName = "newuser";
+ mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(newUserName, result[0]);
+ assertEquals(newPassword, result[1]);
+
+ // the user is set to null, can not change any thing in the future
+ mWebView.setHttpAuthUsernamePassword(host, realm, null, password);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertNull(result[0]);
+ assertEquals(password, result[1]);
+
+ mWebView.setHttpAuthUsernamePassword(host, realm, userName, null);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertNull(result[1]);
+
+ mWebView.setHttpAuthUsernamePassword(host, realm, null, null);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertNull(result[0]);
+ assertNull(result[1]);
+
+ mWebView.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
+ result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(newUserName, result[0]);
+ assertEquals(newPassword, result[1]);
+ } finally {
+ WebViewDatabase.getInstance(mActivity).clearHttpAuthUsernamePassword();
+ }
+ });
}
- @UiThreadTest
+ @Test
public void testWebViewDatabaseAccessHttpAuthUsernamePassword() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- WebViewDatabase webViewDb = WebViewDatabase.getInstance(getActivity());
- try {
- webViewDb.clearHttpAuthUsernamePassword();
-
- String host = "http://localhost:8080";
- String realm = "testrealm";
- String userName = "user";
- String password = "password";
-
- String[] result =
- mWebView.getHttpAuthUsernamePassword(host,
- realm);
- assertNull(result);
-
- webViewDb.setHttpAuthUsernamePassword(host, realm, userName, password);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertEquals(password, result[1]);
-
- String newPassword = "newpassword";
- webViewDb.setHttpAuthUsernamePassword(host, realm, userName, newPassword);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertEquals(newPassword, result[1]);
-
- String newUserName = "newuser";
- webViewDb.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(newUserName, result[0]);
- assertEquals(newPassword, result[1]);
-
- // the user is set to null, can not change any thing in the future
- webViewDb.setHttpAuthUsernamePassword(host, realm, null, password);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertNull(result[0]);
- assertEquals(password, result[1]);
-
- webViewDb.setHttpAuthUsernamePassword(host, realm, userName, null);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(userName, result[0]);
- assertNull(result[1]);
-
- webViewDb.setHttpAuthUsernamePassword(host, realm, null, null);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertNull(result[0]);
- assertNull(result[1]);
-
- webViewDb.setHttpAuthUsernamePassword(host, realm, newUserName, newPassword);
- result = webViewDb.getHttpAuthUsernamePassword(host, realm);
- assertNotNull(result);
- assertEquals(newUserName, result[0]);
- assertEquals(newPassword, result[1]);
- } finally {
- webViewDb.clearHttpAuthUsernamePassword();
- }
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ WebViewDatabase webViewDb = WebViewDatabase.getInstance(mActivity);
+ try {
+ webViewDb.clearHttpAuthUsernamePassword();
+
+ String host = "http://localhost:8080";
+ String realm = "testrealm";
+ String userName = "user";
+ String password = "password";
+
+ String[] result = mWebView.getHttpAuthUsernamePassword(host, realm);
+ assertNull(result);
+
+ webViewDb.setHttpAuthUsernamePassword(host, realm, userName, password);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertEquals(password, result[1]);
+
+ String newPassword = "newpassword";
+ webViewDb.setHttpAuthUsernamePassword(host, realm, userName, newPassword);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertEquals(newPassword, result[1]);
+
+ String newUserName = "newuser";
+ webViewDb.setHttpAuthUsernamePassword(
+ host, realm, newUserName, newPassword);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(newUserName, result[0]);
+ assertEquals(newPassword, result[1]);
+
+ // the user is set to null, can not change any thing in the future
+ webViewDb.setHttpAuthUsernamePassword(host, realm, null, password);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertNull(result[0]);
+ assertEquals(password, result[1]);
+
+ webViewDb.setHttpAuthUsernamePassword(host, realm, userName, null);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(userName, result[0]);
+ assertNull(result[1]);
+
+ webViewDb.setHttpAuthUsernamePassword(host, realm, null, null);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertNull(result[0]);
+ assertNull(result[1]);
+
+ webViewDb.setHttpAuthUsernamePassword(
+ host, realm, newUserName, newPassword);
+ result = webViewDb.getHttpAuthUsernamePassword(host, realm);
+ assertNotNull(result);
+ assertEquals(newUserName, result[0]);
+ assertEquals(newPassword, result[1]);
+ } finally {
+ webViewDb.clearHttpAuthUsernamePassword();
+ }
+ });
}
+ @Test
public void testLoadData() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final String firstTitle = "Hello, World!";
final String HTML_CONTENT =
- "<html><head><title>" + firstTitle + "</title></head><body></body>" +
- "</html>";
- mOnUiThread.loadDataAndWaitForCompletion(HTML_CONTENT,
- "text/html", null);
+ "<html><head><title>" + firstTitle + "</title></head><body></body>" + "</html>";
+ mOnUiThread.loadDataAndWaitForCompletion(HTML_CONTENT, "text/html", null);
assertEquals(firstTitle, mOnUiThread.getTitle());
startWebServer(false);
@@ -1111,20 +1108,25 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.getSettings().setJavaScriptEnabled(true);
final String secondTitle = "Foo bar";
mOnUiThread.loadDataAndWaitForCompletion(
- "<html><head><title>" + secondTitle + "</title></head><body onload=\"" +
- "document.title = " +
- "document.getElementById('frame').contentWindow.location.href;" +
- "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
- "text/html", null);
- assertEquals("Page title should not change, because it should be an error to access a "
- + "cross-site frame's href.",
- secondTitle, mOnUiThread.getTitle());
+ "<html><head><title>"
+ + secondTitle
+ + "</title></head><body onload=\""
+ + "document.title = "
+ + "document.getElementById('frame').contentWindow.location.href;"
+ + "\"><iframe id=\"frame\" src=\""
+ + crossOriginUrl
+ + "\"></body></html>",
+ "text/html",
+ null);
+ assertEquals(
+ "Page title should not change, because it should be an error to access a "
+ + "cross-site frame's href.",
+ secondTitle,
+ mOnUiThread.getTitle());
}
+ @Test
public void testLoadDataWithBaseUrl_resolvesRelativeToBaseUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
assertNull(mOnUiThread.getUrl());
String imgUrl = TestHtmlConstants.SMALL_IMG_URL; // relative
@@ -1135,103 +1137,106 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
startWebServer(false);
final String baseUrl = mWebServer.getAssetUrl("foo.html");
mWebServer.resetRequestState();
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ baseUrl,
HTML_HEADER + "<body><img src=\"" + imgUrl + "\"/></body></html>",
- "text/html", "UTF-8", null);
- assertTrue("The resource request should make it to the server",
+ "text/html",
+ "UTF-8",
+ null);
+ assertTrue(
+ "The resource request should make it to the server",
mWebServer.wasResourceRequested(imgUrl));
}
+ @Test
public void testLoadDataWithBaseUrl_historyUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final String baseUrl = "http://www.baseurl.com/";
final String historyUrl = "http://www.example.com/";
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
- SIMPLE_HTML,
- "text/html", "UTF-8", historyUrl);
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ baseUrl, SIMPLE_HTML, "text/html", "UTF-8", historyUrl);
assertEquals(historyUrl, mOnUiThread.getUrl());
}
+ @Test
public void testLoadDataWithBaseUrl_nullHistoryUrlShowsAsAboutBlank() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Check that reported URL is "about:blank" when supplied history URL
// is null.
final String baseUrl = "http://www.baseurl.com/";
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
- SIMPLE_HTML,
- "text/html", "UTF-8", null);
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ baseUrl, SIMPLE_HTML, "text/html", "UTF-8", null);
assertEquals("about:blank", mOnUiThread.getUrl());
}
+ @Test
public void testLoadDataWithBaseUrl_javascriptCanAccessOrigin() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Test that JavaScript can access content from the same origin as the base URL.
mOnUiThread.getSettings().setJavaScriptEnabled(true);
startWebServer(false);
final String baseUrl = mWebServer.getAssetUrl("foo.html");
final String crossOriginUrl = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
- HTML_HEADER + "<body onload=\"" +
- "document.title = document.getElementById('frame').contentWindow.location.href;" +
- "\"><iframe id=\"frame\" src=\"" + crossOriginUrl + "\"></body></html>",
- "text/html", "UTF-8", null);
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ baseUrl,
+ HTML_HEADER
+ + "<body onload=\"document.title ="
+ + " document.getElementById('frame').contentWindow.location.href;\"><iframe"
+ + " id=\"frame\" src=\""
+ + crossOriginUrl
+ + "\"></body></html>",
+ "text/html",
+ "UTF-8",
+ null);
assertEquals(crossOriginUrl, mOnUiThread.getTitle());
}
+ @Test
public void testLoadDataWithBaseUrl_dataBaseUrlIgnoresHistoryUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Check that when the base URL uses the 'data' scheme, a 'data' scheme URL is used and the
// history URL is ignored.
final String baseUrl = "data:foo";
final String historyUrl = "http://www.example.com/";
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(baseUrl,
- SIMPLE_HTML,
- "text/html", "UTF-8", historyUrl);
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ baseUrl, SIMPLE_HTML, "text/html", "UTF-8", historyUrl);
final String currentUrl = mOnUiThread.getUrl();
- assertEquals("Current URL (" + currentUrl + ") should be a data URI", 0,
+ assertEquals(
+ "Current URL (" + currentUrl + ") should be a data URI",
+ 0,
mOnUiThread.getUrl().indexOf("data:text/html"));
- assertThat("Current URL (" + currentUrl + ") should contain the simple HTML we loaded",
- mOnUiThread.getUrl().indexOf("simple html"), greaterThan(0));
+ assertThat(
+ "Current URL (" + currentUrl + ") should contain the simple HTML we loaded",
+ mOnUiThread.getUrl().indexOf("simple html"),
+ greaterThan(0));
}
+ @Test
public void testLoadDataWithBaseUrl_unencodedContentHttpBaseUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Check that when a non-data: base URL is used, we treat the String to load as
// a raw string and just dump it into the WebView, i.e. not decoding any URL entities.
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("http://www.foo.com",
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ "http://www.foo.com",
HTML_HEADER + "<title>Hello World%21</title><body>bar</body></html>",
- "text/html", "UTF-8", null);
+ "text/html",
+ "UTF-8",
+ null);
assertEquals("Hello World%21", mOnUiThread.getTitle());
}
+ @Test
public void testLoadDataWithBaseUrl_urlEncodedContentDataBaseUrl() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Check that when a data: base URL is used, we treat the String to load as a data: URL
// and run load steps such as decoding URL entities (i.e., contrary to the test case
// above.)
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("data:foo",
- HTML_HEADER + "<title>Hello World%21</title></html>", "text/html", "UTF-8", null);
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ "data:foo",
+ HTML_HEADER + "<title>Hello World%21</title></html>",
+ "text/html",
+ "UTF-8",
+ null);
assertEquals("Hello World!", mOnUiThread.getTitle());
}
+ @Test
public void testLoadDataWithBaseUrl_nullSafe() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(null, null, null, null, null);
assertEquals("about:blank", mOnUiThread.getUrl());
}
@@ -1245,7 +1250,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
private String readTextFile(File file, Charset encoding)
throws FileNotFoundException, IOException {
FileInputStream stream = new FileInputStream(file);
- byte[] bytes = new byte[(int)file.length()];
+ byte[] bytes = new byte[(int) file.length()];
stream.read(bytes);
stream.close();
return new String(bytes, encoding);
@@ -1254,26 +1259,24 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
private void doSaveWebArchive(String baseName, boolean autoName, final String expectName)
throws Throwable {
final Semaphore saving = new Semaphore(0);
- ValueCallback<String> callback = new ValueCallback<String>() {
- @Override
- public void onReceiveValue(String savedName) {
- assertEquals(expectName, savedName);
- saving.release();
- }
- };
+ ValueCallback<String> callback =
+ new ValueCallback<String>() {
+ @Override
+ public void onReceiveValue(String savedName) {
+ assertEquals(expectName, savedName);
+ saving.release();
+ }
+ };
mOnUiThread.saveWebArchive(baseName, autoName, callback);
assertTrue(saving.tryAcquire(WebkitUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
+ @Test
public void testSaveWebArchive() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final String testPage = "testSaveWebArchive test page";
- File dir = getActivity().getFilesDir();
+ File dir = mActivity.getFilesDir();
String dirStr = dir.toString();
File test = new File(dir, "test.mht");
@@ -1324,16 +1327,14 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
}
- private static class WaitForFindResultsListener
- implements WebView.FindListener {
+ private static class WaitForFindResultsListener implements WebView.FindListener {
private final SettableFuture<Integer> mFuture;
private final WebView mWebView;
private final int mMatchesWanted;
private final String mStringWanted;
private final boolean mRetry;
- public WaitForFindResultsListener(
- WebView wv, String wanted, int matches, boolean retry) {
+ WaitForFindResultsListener(WebView wv, String wanted, int matches, boolean retry) {
mFuture = SettableFuture.create();
mWebView = wv;
mMatchesWanted = matches;
@@ -1346,62 +1347,66 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
@Override
- public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
- boolean isDoneCounting) {
+ public void onFindResultReceived(
+ int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) {
try {
- assertEquals("WebView.FindListener callbacks should occur on the UI thread",
- Looper.myLooper(), Looper.getMainLooper());
+ assertEquals(
+ "WebView.FindListener callbacks should occur on the UI thread",
+ Looper.myLooper(),
+ Looper.getMainLooper());
} catch (Throwable t) {
mFuture.setException(t);
}
if (isDoneCounting) {
- //If mRetry set to true and matches aren't equal, call findAll again
+ // If mRetry set to true and matches aren't equal, call findAll again
if (mRetry && numberOfMatches != mMatchesWanted) {
mWebView.findAll(mStringWanted);
- }
- else {
+ } else {
mFuture.set(numberOfMatches);
}
}
}
}
- public void testFindAll() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
+ @Test
+ public void testFindAll() throws Throwable {
// Make the page scrollable, so we can detect the scrolling to make sure the
// content fully loaded.
mOnUiThread.setInitialScale(100);
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
int dimension = Math.max(metrics.widthPixels, metrics.heightPixels);
// create a paragraph high enough to take up the entire screen
- String p = "<p style=\"height:" + dimension + "px;\">" +
- "Find all instances of find on the page and highlight them.</p>";
+ String p =
+ "<p style=\"height:"
+ + dimension
+ + "px;\">"
+ + "Find all instances of find on the page and highlight them.</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "</body></html>", "text/html", null);
WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "find", 2, true);
mOnUiThread.setFindListener(l);
mOnUiThread.findAll("find");
- assertEquals(2, (int)WebkitUtils.waitForFuture(l.future()));
+ assertEquals(2, (int) WebkitUtils.waitForFuture(l.future()));
}
+ @Test
public void testFindNext() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
// Reset the scaling so that finding the next "all" text will require scrolling.
mOnUiThread.setInitialScale(100);
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
int dimension = Math.max(metrics.widthPixels, metrics.heightPixels);
// create a paragraph high enough to take up the entire screen
- String p = "<p style=\"height:" + dimension + "px;\">" +
- "Find all instances of a word on the page and highlight them.</p>";
+ String p =
+ "<p style=\"height:"
+ + dimension
+ + "px;\">"
+ + "Find all instances of a word on the page and highlight them.</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p + p + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + p + "</body></html>", "text/html", null);
WaitForFindResultsListener l = new WaitForFindResultsListener(mWebView, "all", 2, true);
mOnUiThread.setFindListener(l);
@@ -1438,7 +1443,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// clear the result
mOnUiThread.clearMatches();
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
// can not scroll any more
mOnUiThread.findNext(false);
@@ -1450,20 +1455,21 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertEquals(mOnUiThread.getScrollY(), previousScrollY);
}
+ @Test
public void testDocumentHasImages() throws Exception, Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final class DocumentHasImageCheckHandler extends Handler {
private SettableFuture<Integer> mFuture;
+
public DocumentHasImageCheckHandler(Looper looper) {
super(looper);
mFuture = SettableFuture.create();
}
+
@Override
public void handleMessage(Message msg) {
mFuture.set(msg.arg1);
}
+
public Future<Integer> future() {
return mFuture;
}
@@ -1474,17 +1480,20 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// Create a handler on the UI thread.
final DocumentHasImageCheckHandler handler =
- new DocumentHasImageCheckHandler(mWebView.getHandler().getLooper());
-
- WebkitUtils.onMainThreadSync(() -> {
- mOnUiThread.loadDataAndWaitForCompletion("<html><body><img src=\""
- + imgUrl + "\"/></body></html>", "text/html", null);
- Message response = new Message();
- response.setTarget(handler);
- assertFalse(handler.future().isDone());
- mWebView.documentHasImages(response);
- });
- assertEquals(1, (int)WebkitUtils.waitForFuture(handler.future()));
+ new DocumentHasImageCheckHandler(mWebView.getHandler().getLooper());
+
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body><img src=\"" + imgUrl + "\"/></body></html>",
+ "text/html",
+ null);
+ Message response = new Message();
+ response.setTarget(handler);
+ assertFalse(handler.future().isDone());
+ mWebView.documentHasImages(response);
+ });
+ assertEquals(1, (int) WebkitUtils.waitForFuture(handler.future()));
}
private static void waitForFlingDone(WebViewOnUiThread webview) {
@@ -1518,23 +1527,24 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
new ScrollDiffPollingCheck(webview).run();
}
+ @Test
public void testPageScroll() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
- String p = "<p style=\"height:" + dimension + "px;\">" +
- "Scroll by half the size of the page.</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + p + "</body></html>", "text/html", null);
+ String p =
+ "<p style=\"height:"
+ + dimension
+ + "px;\">"
+ + "Scroll by half the size of the page.</p>";
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + p + "</body></html>", "text/html", null);
// Wait for UI thread to settle and receive page dimentions from renderer
// such that we can invoke page down.
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
- return mOnUiThread.pageDown(false);
+ return mOnUiThread.pageDown(false);
}
}.run();
@@ -1565,7 +1575,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// jump to the top
assertTrue(mOnUiThread.pageUp(true));
- new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
+ new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
return topScrollY == mOnUiThread.getScrollY();
@@ -1573,17 +1583,15 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
+ @Test
public void testGetContentHeight() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- mOnUiThread.loadDataAndWaitForCompletion(
- "<html><body></body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion("<html><body></body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
- return mOnUiThread.getScale() != 0 && mOnUiThread.getContentHeight() != 0
- && mOnUiThread.getHeight() != 0;
+ return mOnUiThread.getScale() != 0
+ && mOnUiThread.getContentHeight() != 0
+ && mOnUiThread.getHeight() != 0;
}
}.run();
@@ -1611,14 +1619,17 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
final float scaleFactor = Math.max(1.0f, 1.0f / mOnUiThread.getScale());
final int pageHeight =
- (int)(Math.ceil(Math.max(metrics.widthPixels, metrics.heightPixels)
- * scaleFactor));
+ (int)
+ (Math.ceil(
+ Math.max(metrics.widthPixels, metrics.heightPixels) * scaleFactor));
// set the margin to 0
- final String p = "<p style=\"height:" + pageHeight
- + "px;margin:0px auto;\">Get the height of HTML content.</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "</body></html>", "text/html", null);
+ final String p =
+ "<p style=\"height:"
+ + pageHeight
+ + "px;margin:0px auto;\">Get the height of HTML content.</p>";
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -1627,8 +1638,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
final int extraSpace = mOnUiThread.getContentHeight() - pageHeight;
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + p + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + p + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -1643,53 +1654,57 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
- @UiThreadTest
+ @Test
public void testPlatformNotifications() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- WebView.enablePlatformNotifications();
- WebView.disablePlatformNotifications();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ WebView.enablePlatformNotifications();
+ WebView.disablePlatformNotifications();
+ });
}
- @UiThreadTest
+ @Test
public void testAccessPluginList() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- assertNotNull(WebView.getPluginList());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ assertNotNull(WebView.getPluginList());
- // can not find a way to install plugins
- mWebView.refreshPlugins(false);
+ // can not find a way to install plugins
+ mWebView.refreshPlugins(false);
+ });
}
- @UiThreadTest
+ @Test
public void testDestroy() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- // Create a new WebView, since we cannot call destroy() on a view in the hierarchy
- WebView localWebView = new WebView(getActivity());
- localWebView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ // Create a new WebView, since we cannot call destroy() on a view in the
+ // hierarchy
+ WebView localWebView = new WebView(mActivity);
+ localWebView.destroy();
+ });
}
+ @Test
public void testFlingScroll() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
final int dimension = 10 * Math.max(metrics.widthPixels, metrics.heightPixels);
- String p = "<p style=\"height:" + dimension + "px;" +
- "width:" + dimension + "px\">Test fling scroll.</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "</body></html>", "text/html", null);
+ String p =
+ "<p style=\"height:"
+ + dimension
+ + "px;"
+ + "width:"
+ + dimension
+ + "px\">Test fling scroll.</p>";
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
return mOnUiThread.getContentHeight() >= dimension;
}
}.run();
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
final int previousScrollX = mOnUiThread.getScrollX();
final int previousScrollY = mOnUiThread.getScrollY();
@@ -1699,24 +1714,27 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
- return mOnUiThread.getScrollX() > previousScrollX &&
- mOnUiThread.getScrollY() > previousScrollY;
+ return mOnUiThread.getScrollX() > previousScrollX
+ && mOnUiThread.getScrollY() > previousScrollY;
}
}.run();
}
+ @Test
public void testRequestFocusNodeHref() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
startWebServer(false);
+
String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
- final String links = "<DL><p><DT><A HREF=\"" + url1
- + "\">HTML_URL1</A><DT><A HREF=\"" + url2
- + "\">HTML_URL2</A></DL><p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + links + "</body></html>", "text/html", null);
- getInstrumentation().waitForIdleSync();
+ final String links =
+ "<DL><p><DT><A HREF=\""
+ + url1
+ + "\">HTML_URL1</A><DT><A HREF=\""
+ + url2
+ + "\">HTML_URL2</A></DL><p>";
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + links + "</body></html>", "text/html", null);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
final Message hrefMsg = new Message();
@@ -1724,7 +1742,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
// focus on first link
handler.reset();
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
+ InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
mOnUiThread.requestFocusNodeHref(hrefMsg);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1749,7 +1767,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
handler.reset();
final Message hrefMsg2 = new Message();
hrefMsg2.setTarget(handler);
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
+ InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
mOnUiThread.requestFocusNodeHref(hrefMsg2);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1757,8 +1775,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
boolean done = false;
final String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
if (handler.hasCalledHandleMessage()) {
- if (handler.mResultUrl != null &&
- handler.mResultUrl.equals(url2)) {
+ if (handler.mResultUrl != null && handler.mResultUrl.equals(url2)) {
done = true;
} else {
handler.reset();
@@ -1775,10 +1792,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.requestFocusNodeHref(null);
}
+ @Test
public void testRequestImageRef() throws Exception, Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final class ImageLoaded {
public SettableFuture<Void> mImageLoaded = SettableFuture.create();
@@ -1799,19 +1814,22 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
final String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.LARGE_IMG_URL);
mOnUiThread.loadDataAndWaitForCompletion(
"<html><head><title>Title</title><style type='text/css'>"
- + "%23imgElement { -webkit-transform: translate3d(0,0,1); }"
- + "%23imgElement.finish { -webkit-transform: translate3d(0,0,0);"
- + " -webkit-transition-duration: 1ms; }</style>"
- + "<script type='text/javascript'>function imgLoad() {"
- + "imgElement = document.getElementById('imgElement');"
- + "imgElement.addEventListener('webkitTransitionEnd',"
- + "function(e) { imageLoaded.loaded(); });"
- + "imgElement.className = 'finish';}</script>"
- + "</head><body><img id='imgElement' src='" + imgUrl
- + "' width='100%' height='100%' onLoad='imgLoad()'/>"
- + "</body></html>", "text/html", null);
+ + "%23imgElement { -webkit-transform: translate3d(0,0,1); }"
+ + "%23imgElement.finish { -webkit-transform: translate3d(0,0,0);"
+ + " -webkit-transition-duration: 1ms; }</style>"
+ + "<script type='text/javascript'>function imgLoad() {"
+ + "imgElement = document.getElementById('imgElement');"
+ + "imgElement.addEventListener('webkitTransitionEnd',"
+ + "function(e) { imageLoaded.loaded(); });"
+ + "imgElement.className = 'finish';}</script>"
+ + "</head><body><img id='imgElement' src='"
+ + imgUrl
+ + "' width='100%' height='100%' onLoad='imgLoad()'/>"
+ + "</body></html>",
+ "text/html",
+ null);
WebkitUtils.waitForFuture(imageLoaded.future());
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
final Message msg = new Message();
@@ -1824,10 +1842,11 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
int middleY = location[1] + mOnUiThread.getWebView().getHeight() / 2;
long time = SystemClock.uptimeMillis();
- getInstrumentation().sendPointerSync(
- MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN,
- middleX, middleY, 0));
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation()
+ .sendPointerSync(
+ MotionEvent.obtain(
+ time, time, MotionEvent.ACTION_DOWN, middleX, middleY, 0));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
mOnUiThread.requestImageRef(msg);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1849,23 +1868,22 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertEquals(imgUrl, handler.mResultUrl);
}
- @UiThreadTest
+ @Test
public void testDebugDump() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- mWebView.debugDump();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ mWebView.debugDump();
+ });
}
+ @Test
public void testGetHitTestResult() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- final String anchor = "<p><a href=\"" + TestHtmlConstants.EXT_WEB_URL1
- + "\">normal anchor</a></p>";
+ final String anchor =
+ "<p><a href=\"" + TestHtmlConstants.EXT_WEB_URL1 + "\">normal anchor</a></p>";
final String blankAnchor = "<p><a href=\"\">blank anchor</a></p>";
- final String form = "<p><form><input type=\"text\" name=\"Test\"><br>"
- + "<input type=\"submit\" value=\"Submit\"></form></p>";
+ final String form =
+ "<p><form><input type=\"text\" name=\"Test\"><br>"
+ + "<input type=\"submit\" value=\"Submit\"></form></p>";
String phoneNo = "3106984000";
final String tel = "<p><a href=\"tel:" + phoneNo + "\">Phone</a></p>";
String email = "test@gmail.com";
@@ -1873,10 +1891,20 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
String location = "shanghai";
final String geo = "<p><a href=\"geo:0,0?q=" + location + "\">Location</a></p>";
- mOnUiThread.loadDataWithBaseURLAndWaitForCompletion("fake://home",
- "<html><body>" + anchor + blankAnchor + form + tel + mailto +
- geo + "</body></html>", "text/html", "UTF-8", null);
- getInstrumentation().waitForIdleSync();
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(
+ "fake://home",
+ "<html><body>"
+ + anchor
+ + blankAnchor
+ + form
+ + tel
+ + mailto
+ + geo
+ + "</body></html>",
+ "text/html",
+ "UTF-8",
+ null);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
// anchor
moveFocusDown();
@@ -1921,16 +1949,13 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertEquals(location, hitTestResult.getExtra());
}
+ @Test
public void testSetInitialScale() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
final String p = "<p style=\"height:1000px;width:1000px\">Test setInitialScale.</p>";
- final float defaultScale =
- getActivity().getResources().getDisplayMetrics().density;
+ final float defaultScale = mActivity.getResources().getDisplayMetrics().density;
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1941,8 +1966,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.setInitialScale(0);
// modify content to fool WebKit into re-loading
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "2" + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "2" + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1952,8 +1977,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
mOnUiThread.setInitialScale(50);
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "3" + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "3" + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1963,8 +1988,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
mOnUiThread.setInitialScale(0);
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "4" + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "4" + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
@@ -1974,112 +1999,112 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
- @UiThreadTest
+ @Test
public void testClearHistory() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
startWebServer(false);
- String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
- String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
- String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
- mOnUiThread.loadUrlAndWaitForCompletion(url1);
- pollingCheckWebBackForwardList(url1, 0, 1);
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
+ String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
+ String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
- mOnUiThread.loadUrlAndWaitForCompletion(url2);
- pollingCheckWebBackForwardList(url2, 1, 2);
+ mOnUiThread.loadUrlAndWaitForCompletion(url1);
+ pollingCheckWebBackForwardList(url1, 0, 1);
- mOnUiThread.loadUrlAndWaitForCompletion(url3);
- pollingCheckWebBackForwardList(url3, 2, 3);
+ mOnUiThread.loadUrlAndWaitForCompletion(url2);
+ pollingCheckWebBackForwardList(url2, 1, 2);
- mWebView.clearHistory();
+ mOnUiThread.loadUrlAndWaitForCompletion(url3);
+ pollingCheckWebBackForwardList(url3, 2, 3);
- // only current URL is left after clearing
- pollingCheckWebBackForwardList(url3, 0, 1);
+ mWebView.clearHistory();
+
+ // only current URL is left after clearing
+ pollingCheckWebBackForwardList(url3, 0, 1);
+ });
}
- @UiThreadTest
+ @Test
public void testSaveAndRestoreState() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- assertNull("Should return null when there's nothing to save",
- mWebView.saveState(new Bundle()));
-
startWebServer(false);
- String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
- String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
- String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
-
- // make a history list
- mOnUiThread.loadUrlAndWaitForCompletion(url1);
- pollingCheckWebBackForwardList(url1, 0, 1);
- mOnUiThread.loadUrlAndWaitForCompletion(url2);
- pollingCheckWebBackForwardList(url2, 1, 2);
- mOnUiThread.loadUrlAndWaitForCompletion(url3);
- pollingCheckWebBackForwardList(url3, 2, 3);
-
- // save the list
- Bundle bundle = new Bundle();
- WebBackForwardList saveList = mWebView.saveState(bundle);
- assertNotNull(saveList);
- assertEquals(3, saveList.getSize());
- assertEquals(2, saveList.getCurrentIndex());
- assertEquals(url1, saveList.getItemAtIndex(0).getUrl());
- assertEquals(url2, saveList.getItemAtIndex(1).getUrl());
- assertEquals(url3, saveList.getItemAtIndex(2).getUrl());
-
- // change the content to a new "blank" web view without history
- final WebView newWebView = new WebView(getActivity());
-
- WebBackForwardList copyListBeforeRestore = newWebView.copyBackForwardList();
- assertNotNull(copyListBeforeRestore);
- assertEquals(0, copyListBeforeRestore.getSize());
-
- // restore the list
- final WebBackForwardList restoreList = newWebView.restoreState(bundle);
- assertNotNull(restoreList);
- assertEquals(3, restoreList.getSize());
- assertEquals(2, saveList.getCurrentIndex());
-
- // wait for the list items to get inflated
- new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
- @Override
- protected boolean check() {
- return restoreList.getItemAtIndex(0).getUrl() != null &&
- restoreList.getItemAtIndex(1).getUrl() != null &&
- restoreList.getItemAtIndex(2).getUrl() != null;
- }
- }.run();
- assertEquals(url1, restoreList.getItemAtIndex(0).getUrl());
- assertEquals(url2, restoreList.getItemAtIndex(1).getUrl());
- assertEquals(url3, restoreList.getItemAtIndex(2).getUrl());
- WebBackForwardList copyListAfterRestore = newWebView.copyBackForwardList();
- assertNotNull(copyListAfterRestore);
- assertEquals(3, copyListAfterRestore.getSize());
- assertEquals(2, copyListAfterRestore.getCurrentIndex());
- assertEquals(url1, copyListAfterRestore.getItemAtIndex(0).getUrl());
- assertEquals(url2, copyListAfterRestore.getItemAtIndex(1).getUrl());
- assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
-
- newWebView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ assertNull(
+ "Should return null when there's nothing to save",
+ mWebView.saveState(new Bundle()));
+
+ String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
+ String url2 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL2);
+ String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
+
+ // make a history list
+ mOnUiThread.loadUrlAndWaitForCompletion(url1);
+ pollingCheckWebBackForwardList(url1, 0, 1);
+ mOnUiThread.loadUrlAndWaitForCompletion(url2);
+ pollingCheckWebBackForwardList(url2, 1, 2);
+ mOnUiThread.loadUrlAndWaitForCompletion(url3);
+ pollingCheckWebBackForwardList(url3, 2, 3);
+
+ // save the list
+ Bundle bundle = new Bundle();
+ WebBackForwardList saveList = mWebView.saveState(bundle);
+ assertNotNull(saveList);
+ assertEquals(3, saveList.getSize());
+ assertEquals(2, saveList.getCurrentIndex());
+ assertEquals(url1, saveList.getItemAtIndex(0).getUrl());
+ assertEquals(url2, saveList.getItemAtIndex(1).getUrl());
+ assertEquals(url3, saveList.getItemAtIndex(2).getUrl());
+
+ // change the content to a new "blank" web view without history
+ final WebView newWebView = new WebView(mActivity);
+
+ WebBackForwardList copyListBeforeRestore = newWebView.copyBackForwardList();
+ assertNotNull(copyListBeforeRestore);
+ assertEquals(0, copyListBeforeRestore.getSize());
+
+ // restore the list
+ final WebBackForwardList restoreList = newWebView.restoreState(bundle);
+ assertNotNull(restoreList);
+ assertEquals(3, restoreList.getSize());
+ assertEquals(2, saveList.getCurrentIndex());
+
+ // wait for the list items to get inflated
+ new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
+ @Override
+ protected boolean check() {
+ return restoreList.getItemAtIndex(0).getUrl() != null
+ && restoreList.getItemAtIndex(1).getUrl() != null
+ && restoreList.getItemAtIndex(2).getUrl() != null;
+ }
+ }.run();
+ assertEquals(url1, restoreList.getItemAtIndex(0).getUrl());
+ assertEquals(url2, restoreList.getItemAtIndex(1).getUrl());
+ assertEquals(url3, restoreList.getItemAtIndex(2).getUrl());
+
+ WebBackForwardList copyListAfterRestore = newWebView.copyBackForwardList();
+ assertNotNull(copyListAfterRestore);
+ assertEquals(3, copyListAfterRestore.getSize());
+ assertEquals(2, copyListAfterRestore.getCurrentIndex());
+ assertEquals(url1, copyListAfterRestore.getItemAtIndex(0).getUrl());
+ assertEquals(url2, copyListAfterRestore.getItemAtIndex(1).getUrl());
+ assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
+
+ newWebView.destroy();
+ });
}
+ @Test
public void testRequestChildRectangleOnScreen() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
// It is needed to make test pass on some devices.
mOnUiThread.setLayoutToMatchParent();
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
String p = "<p style=\"height:" + dimension + "px;width:" + dimension + "px\">&nbsp;</p>";
- mOnUiThread.loadDataAndWaitForCompletion("<html><body>" + p
- + "</body></html>", "text/html", null);
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><body>" + p + "</body></html>", "text/html", null);
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -2097,11 +2122,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertThat(mOnUiThread.getScrollY(), greaterThan(origY));
}
+ @Test
public void testSetDownloadListener() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final SettableFuture<Void> downloadStartFuture = SettableFuture.create();
final class MyDownloadListener implements DownloadListener {
public String url;
@@ -2110,8 +2132,12 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
public String contentDisposition;
@Override
- public void onDownloadStart(String url, String userAgent, String contentDisposition,
- String mimetype, long contentLength) {
+ public void onDownloadStart(
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ long contentLength) {
this.url = url;
this.mimeType = mimetype;
this.contentLength = contentLength;
@@ -2135,9 +2161,10 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.loadDataAndWaitForCompletion(
"<html><body onload=\"window.location = \'" + url + "\'\"></body></html>",
- "text/html", null);
+ "text/html",
+ null);
// Wait for layout to complete before setting focus.
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
WebkitUtils.waitForFuture(downloadStartFuture);
assertEquals(url, listener.url);
@@ -2146,28 +2173,26 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
assertEquals(mimeType, listener.mimeType);
}
- @UiThreadTest
+ @Test
public void testSetLayoutParams() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(600, 800);
- mWebView.setLayoutParams(params);
- assertSame(params, mWebView.getLayoutParams());
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(600, 800);
+ mWebView.setLayoutParams(params);
+ assertSame(params, mWebView.getLayoutParams());
+ });
}
- @UiThreadTest
+ @Test
public void testSetMapTrackballToArrowKeys() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- mWebView.setMapTrackballToArrowKeys(true);
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ mWebView.setMapTrackballToArrowKeys(true);
+ });
}
+ @Test
public void testSetNetworkAvailable() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
WebSettings settings = mOnUiThread.getSettings();
settings.setJavaScriptEnabled(true);
startWebServer(false);
@@ -2197,42 +2222,39 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
+ @Test
public void testSetWebChromeClient() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final SettableFuture<Void> future = SettableFuture.create();
- mOnUiThread.setWebChromeClient(new WaitForProgressClient(mOnUiThread) {
- @Override
- public void onProgressChanged(WebView view, int newProgress) {
- super.onProgressChanged(view, newProgress);
- future.set(null);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mOnUiThread.setWebChromeClient(
+ new WaitForProgressClient(mOnUiThread) {
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ super.onProgressChanged(view, newProgress);
+ future.set(null);
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
assertFalse(future.isDone());
startWebServer(false);
final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
mOnUiThread.loadUrlAndWaitForCompletion(url);
- getInstrumentation().waitForIdleSync();
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
WebkitUtils.waitForFuture(future);
}
+ @Test
public void testPauseResumeTimers() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
class Monitor {
private boolean mIsUpdated;
@JavascriptInterface
public synchronized void update() {
- mIsUpdated = true;
+ mIsUpdated = true;
notify();
}
+
public synchronized boolean waitForUpdate() {
while (!mIsUpdated) {
try {
@@ -2249,25 +2271,28 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
mIsUpdated = false;
return true;
}
- };
+ }
+
final Monitor monitor = new Monitor();
- final String updateMonitorHtml = "<html>" +
- "<body onload=\"monitor.update();\"></body></html>";
+ final String updateMonitorHtml =
+ "<html>" + "<body onload=\"monitor.update();\"></body></html>";
// Test that JavaScript is executed even with timers paused.
- WebkitUtils.onMainThreadSync(() -> {
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.addJavascriptInterface(monitor, "monitor");
- mWebView.pauseTimers();
- mOnUiThread.loadDataAndWaitForCompletion(updateMonitorHtml,
- "text/html", null);
- });
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ mWebView.addJavascriptInterface(monitor, "monitor");
+ mWebView.pauseTimers();
+ mOnUiThread.loadDataAndWaitForCompletion(updateMonitorHtml, "text/html", null);
+ });
assertTrue(monitor.waitForUpdate());
// Start a timer and test that it does not fire.
mOnUiThread.loadDataAndWaitForCompletion(
- "<html><body onload='setTimeout(function(){monitor.update();},100)'>" +
- "</body></html>", "text/html", null);
+ "<html><body onload='setTimeout(function(){monitor.update();},100)'>"
+ + "</body></html>",
+ "text/html",
+ null);
assertFalse(monitor.waitForUpdate());
// Resume timers and test that the timer fires.
@@ -2276,37 +2301,31 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
// verify query parameters can be passed correctly to android asset files
+ @Test
public void testAndroidAssetQueryParam() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
WebSettings settings = mOnUiThread.getSettings();
settings.setJavaScriptEnabled(true);
// test passing a parameter
- String fileUrl = TestHtmlConstants.getFileUrl(TestHtmlConstants.PARAM_ASSET_URL+"?val=SUCCESS");
+ String fileUrl =
+ TestHtmlConstants.getFileUrl(TestHtmlConstants.PARAM_ASSET_URL + "?val=SUCCESS");
mOnUiThread.loadUrlAndWaitForCompletion(fileUrl);
assertEquals("SUCCESS", mOnUiThread.getTitle());
}
// verify anchors work correctly for android asset files
+ @Test
public void testAndroidAssetAnchor() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
WebSettings settings = mOnUiThread.getSettings();
settings.setJavaScriptEnabled(true);
// test using an anchor
- String fileUrl = TestHtmlConstants.getFileUrl(TestHtmlConstants.ANCHOR_ASSET_URL+"#anchor");
+ String fileUrl =
+ TestHtmlConstants.getFileUrl(TestHtmlConstants.ANCHOR_ASSET_URL + "#anchor");
mOnUiThread.loadUrlAndWaitForCompletion(fileUrl);
assertEquals("anchor", mOnUiThread.getTitle());
}
+ @Test
public void testEvaluateJavascript() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
@@ -2325,26 +2344,27 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
// Verify Print feature can create a PDF file with a correct preamble.
+ @Test
public void testPrinting() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
- mOnUiThread.loadDataAndWaitForCompletion("<html><head></head>" +
- "<body>foo</body></html>",
- "text/html", null);
- final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
+ mOnUiThread.loadDataAndWaitForCompletion(
+ "<html><head></head>" + "<body>foo</body></html>", "text/html", null);
+ final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
printDocumentStart(adapter);
- PrintAttributes attributes = new PrintAttributes.Builder()
- .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
- .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
- .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
- .build();
- final WebViewCtsActivity activity = getActivity();
+ PrintAttributes attributes =
+ new PrintAttributes.Builder()
+ .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+ .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
+ .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+ .build();
+ final WebViewCtsActivity activity = mActivity;
final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
- final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
- ParcelFileDescriptor.parseMode("w"));
+ final ParcelFileDescriptor descriptor =
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode("w"));
final SettableFuture<Void> result = SettableFuture.create();
- printDocumentLayout(adapter, null, attributes,
+ printDocumentLayout(
+ adapter,
+ null,
+ attributes,
new LayoutResultCallback() {
// Called on UI thread
@Override
@@ -2369,44 +2389,46 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
// Verify Print feature can create a PDF file with correct number of pages.
+ @Test
public void testPrintingPagesCount() throws Throwable {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
String content = "<html><head></head><body>";
for (int i = 0; i < 500; ++i) {
content += "<br />abcdefghijk<br />";
}
content += "</body></html>";
mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
- final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
+ final PrintDocumentAdapter adapter = mOnUiThread.createPrintDocumentAdapter();
printDocumentStart(adapter);
- PrintAttributes attributes = new PrintAttributes.Builder()
- .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
- .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
- .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
- .build();
- final WebViewCtsActivity activity = getActivity();
+ PrintAttributes attributes =
+ new PrintAttributes.Builder()
+ .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
+ .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
+ .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
+ .build();
+ final WebViewCtsActivity activity = mActivity;
final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
- final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
- ParcelFileDescriptor.parseMode("w"));
+ final ParcelFileDescriptor descriptor =
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode("w"));
final SettableFuture<Void> result = SettableFuture.create();
- printDocumentLayout(adapter, null, attributes,
+ printDocumentLayout(
+ adapter,
+ null,
+ attributes,
new LayoutResultCallback() {
// Called on UI thread
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- PageRange[] pageRanges = new PageRange[] {
- new PageRange(1, 1), new PageRange(4, 7)
- };
+ PageRange[] pageRanges =
+ new PageRange[] {new PageRange(1, 1), new PageRange(4, 7)};
savePrintedPage(adapter, descriptor, pageRanges, result);
}
});
try {
WebkitUtils.waitForFuture(result);
assertThat(file.length(), greaterThan(0L));
- PdfRenderer renderer = new PdfRenderer(
- ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
+ PdfRenderer renderer =
+ new PdfRenderer(
+ ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
assertEquals(5, renderer.getPageCount());
} finally {
descriptor.close();
@@ -2419,34 +2441,35 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* androidx.webkit.WebViewCompatTest#testVisualStateCallbackCalled. Modifications to this test
* should be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
+ @Test
public void testVisualStateCallbackCalled() throws Exception {
// Check that the visual state callback is called correctly.
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final long kRequest = 100;
mOnUiThread.loadUrl("about:blank");
final SettableFuture<Long> visualStateFuture = SettableFuture.create();
- mOnUiThread.postVisualStateCallback(kRequest, new VisualStateCallback() {
- public void onComplete(long requestId) {
- visualStateFuture.set(requestId);
- }
- });
+ mOnUiThread.postVisualStateCallback(
+ kRequest,
+ new VisualStateCallback() {
+ public void onComplete(long requestId) {
+ visualStateFuture.set(requestId);
+ }
+ });
assertEquals(kRequest, (long) WebkitUtils.waitForFuture(visualStateFuture));
}
private static boolean setSafeBrowsingAllowlistSync(List<String> allowlist) {
final SettableFuture<Boolean> safeBrowsingAllowlistFuture = SettableFuture.create();
- WebView.setSafeBrowsingWhitelist(allowlist, new ValueCallback<Boolean>() {
- @Override
- public void onReceiveValue(Boolean success) {
- safeBrowsingAllowlistFuture.set(success);
- }
- });
+ WebView.setSafeBrowsingWhitelist(
+ allowlist,
+ new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean success) {
+ safeBrowsingAllowlistFuture.set(success);
+ }
+ });
return WebkitUtils.waitForFuture(safeBrowsingAllowlistFuture);
}
@@ -2456,11 +2479,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* Modifications to this test should be reflected in that test as necessary. See
* http://go/modifying-webview-cts.
*/
+ @Test
public void testSetSafeBrowsingAllowlistWithMalformedList() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
List allowlist = new ArrayList<String>();
// Protocols are not supported in the allowlist
allowlist.add("http://google.com");
@@ -2469,33 +2489,35 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
/**
* This should remain functionally equivalent to
- * androidx.webkit.WebViewCompatTest#testSetSafeBrowsingAllowlistWithValidList. Modifications
- * to this test should be reflected in that test as necessary. See
- * http://go/modifying-webview-cts.
+ * androidx.webkit.WebViewCompatTest#testSetSafeBrowsingAllowlistWithValidList. Modifications to
+ * this test should be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
+ @Test
public void testSetSafeBrowsingAllowlistWithValidList() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
List allowlist = new ArrayList<String>();
allowlist.add("safe-browsing");
assertTrue("Valid allowlist should be successful", setSafeBrowsingAllowlistSync(allowlist));
final SettableFuture<Void> pageFinishedFuture = SettableFuture.create();
- mOnUiThread.setWebViewClient(new WebViewClient() {
- @Override
- public void onPageFinished(WebView view, String url) {
- pageFinishedFuture.set(null);
- }
+ mOnUiThread.setWebViewClient(
+ new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ pageFinishedFuture.set(null);
+ }
- @Override
- public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
- SafeBrowsingResponse callback) {
- pageFinishedFuture.setException(new IllegalStateException(
- "Should not invoke onSafeBrowsingHit for " + request.getUrl()));
- }
- });
+ @Override
+ public void onSafeBrowsingHit(
+ WebView view,
+ WebResourceRequest request,
+ int threatType,
+ SafeBrowsingResponse callback) {
+ pageFinishedFuture.setException(
+ new IllegalStateException(
+ "Should not invoke onSafeBrowsingHit for "
+ + request.getUrl()));
+ }
+ });
mOnUiThread.loadUrl("chrome://safe-browsing/match?type=malware");
@@ -2508,24 +2530,24 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* androidx.webkit.WebViewCompatTest#testGetWebViewClient. Modifications to this test should be
* reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
- @UiThreadTest
+ @Test
public void testGetWebViewClient() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- // getWebViewClient should return a default WebViewClient if it hasn't been set yet
- WebView webView = new WebView(getActivity());
- WebViewClient client = webView.getWebViewClient();
- assertNotNull(client);
- assertTrue(client instanceof WebViewClient);
-
- // getWebViewClient should return the client after it has been set
- WebViewClient client2 = new WebViewClient();
- assertNotSame(client, client2);
- webView.setWebViewClient(client2);
- assertSame(client2, webView.getWebViewClient());
- webView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ // getWebViewClient should return a default WebViewClient if it hasn't been set
+ // yet
+ WebView webView = new WebView(mActivity);
+ WebViewClient client = webView.getWebViewClient();
+ assertNotNull(client);
+ assertTrue(client instanceof WebViewClient);
+
+ // getWebViewClient should return the client after it has been set
+ WebViewClient client2 = new WebViewClient();
+ assertNotSame(client, client2);
+ webView.setWebViewClient(client2);
+ assertSame(client2, webView.getWebViewClient());
+ webView.destroy();
+ });
}
/**
@@ -2533,56 +2555,48 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* androidx.webkit.WebViewCompatTest#testGetWebChromeClient. Modifications to this test should
* be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
- @UiThreadTest
+ @Test
public void testGetWebChromeClient() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- // getWebChromeClient should return null if the client hasn't been set yet
- WebView webView = new WebView(getActivity());
- WebChromeClient client = webView.getWebChromeClient();
- assertNull(client);
-
- // getWebChromeClient should return the client after it has been set
- WebChromeClient client2 = new WebChromeClient();
- assertNotSame(client, client2);
- webView.setWebChromeClient(client2);
- assertSame(client2, webView.getWebChromeClient());
- webView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ // getWebChromeClient should return null if the client hasn't been set yet
+ WebView webView = new WebView(mActivity);
+ WebChromeClient client = webView.getWebChromeClient();
+ assertNull(client);
+
+ // getWebChromeClient should return the client after it has been set
+ WebChromeClient client2 = new WebChromeClient();
+ assertNotSame(client, client2);
+ webView.setWebChromeClient(client2);
+ assertSame(client2, webView.getWebChromeClient());
+ webView.destroy();
+ });
}
- @UiThreadTest
+ @Test
public void testSetCustomTextClassifier() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
class CustomTextClassifier implements TextClassifier {
@Override
public TextSelection suggestSelection(
- CharSequence text,
- int startIndex,
- int endIndex,
- LocaleList defaultLocales) {
+ CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
return new TextSelection.Builder(0, 1).build();
}
@Override
public TextClassification classifyText(
- CharSequence text,
- int startIndex,
- int endIndex,
- LocaleList defaultLocales) {
+ CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
return new TextClassification.Builder().build();
}
- };
+ }
- TextClassifier classifier = new CustomTextClassifier();
- WebView webView = new WebView(getActivity());
- webView.setTextClassifier(classifier);
- assertSame(webView.getTextClassifier(), classifier);
- webView.destroy();
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ TextClassifier classifier = new CustomTextClassifier();
+ WebView webView = new WebView(mActivity);
+ webView.setTextClassifier(classifier);
+ assertSame(webView.getTextClassifier(), classifier);
+ webView.destroy();
+ });
}
private static class MockContext extends ContextWrapper {
@@ -2604,23 +2618,25 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
/**
* This should remain functionally equivalent to
- * androidx.webkit.WebViewCompatTest#testStartSafeBrowsingUseApplicationContext. Modifications to
- * this test should be reflected in that test as necessary. See http://go/modifying-webview-cts.
+ * androidx.webkit.WebViewCompatTest#testStartSafeBrowsingUseApplicationContext. Modifications
+ * to this test should be reflected in that test as necessary. See
+ * http://go/modifying-webview-cts.
*/
+ @Test
public void testStartSafeBrowsingUseApplicationContext() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- final MockContext ctx = new MockContext(getActivity());
+ final MockContext ctx =
+ new MockContext(
+ ApplicationProvider.getApplicationContext().getApplicationContext());
final SettableFuture<Boolean> startSafeBrowsingFuture = SettableFuture.create();
- WebView.startSafeBrowsing(ctx, new ValueCallback<Boolean>() {
- @Override
- public void onReceiveValue(Boolean value) {
- startSafeBrowsingFuture.set(ctx.wasGetApplicationContextCalled());
- return;
- }
- });
+ WebView.startSafeBrowsing(
+ ctx,
+ new ValueCallback<Boolean>() {
+ @Override
+ public void onReceiveValue(Boolean value) {
+ startSafeBrowsingFuture.set(ctx.wasGetApplicationContextCalled());
+ return;
+ }
+ });
assertTrue(WebkitUtils.waitForFuture(startSafeBrowsingFuture));
}
@@ -2630,40 +2646,40 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* Modifications to this test should be reflected in that test as necessary. See
* http://go/modifying-webview-cts.
*/
+ @Test
public void testStartSafeBrowsingWithNullCallbackDoesntCrash() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
- WebView.startSafeBrowsing(getActivity().getApplicationContext(), null);
+ WebView.startSafeBrowsing(
+ ApplicationProvider.getApplicationContext().getApplicationContext(), null);
}
/**
* This should remain functionally equivalent to
- * androidx.webkit.WebViewCompatTest#testStartSafeBrowsingInvokesCallback. Modifications to
- * this test should be reflected in that test as necessary. See http://go/modifying-webview-cts.
+ * androidx.webkit.WebViewCompatTest#testStartSafeBrowsingInvokesCallback. Modifications to this
+ * test should be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
+ @Test
public void testStartSafeBrowsingInvokesCallback() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
final SettableFuture<Boolean> startSafeBrowsingFuture = SettableFuture.create();
- WebView.startSafeBrowsing(getActivity().getApplicationContext(),
+ WebView.startSafeBrowsing(
+ ApplicationProvider.getApplicationContext().getApplicationContext(),
new ValueCallback<Boolean>() {
- @Override
- public void onReceiveValue(Boolean value) {
- startSafeBrowsingFuture.set(Looper.getMainLooper().isCurrentThread());
- return;
- }
- });
+ @Override
+ public void onReceiveValue(Boolean value) {
+ startSafeBrowsingFuture.set(Looper.getMainLooper().isCurrentThread());
+ return;
+ }
+ });
assertTrue(WebkitUtils.waitForFuture(startSafeBrowsingFuture));
}
- private void savePrintedPage(final PrintDocumentAdapter adapter,
- final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
+ private void savePrintedPage(
+ final PrintDocumentAdapter adapter,
+ final ParcelFileDescriptor descriptor,
+ final PageRange[] pageRanges,
final SettableFuture<Void> result) {
- adapter.onWrite(pageRanges, descriptor,
+ adapter.onWrite(
+ pageRanges,
+ descriptor,
new CancellationSignal(),
new WriteResultCallback() {
@Override
@@ -2679,18 +2695,26 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
private void printDocumentStart(final PrintDocumentAdapter adapter) {
- WebkitUtils.onMainThreadSync(() -> {
- adapter.onStart();
- });
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ adapter.onStart();
+ });
}
- private void printDocumentLayout(final PrintDocumentAdapter adapter,
- final PrintAttributes oldAttributes, final PrintAttributes newAttributes,
+ private void printDocumentLayout(
+ final PrintDocumentAdapter adapter,
+ final PrintAttributes oldAttributes,
+ final PrintAttributes newAttributes,
final LayoutResultCallback layoutResultCallback) {
- WebkitUtils.onMainThreadSync(() -> {
- adapter.onLayout(oldAttributes, newAttributes, new CancellationSignal(),
- layoutResultCallback, null);
- });
+ WebkitUtils.onMainThreadSync(
+ () -> {
+ adapter.onLayout(
+ oldAttributes,
+ newAttributes,
+ new CancellationSignal(),
+ layoutResultCallback,
+ null);
+ });
}
private static class HrefCheckHandler extends Handler {
@@ -2710,7 +2734,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
return mResultUrl;
}
- public void reset(){
+ public void reset() {
mResultUrl = null;
mHadRecieved = false;
}
@@ -2724,13 +2748,13 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
private void moveFocusDown() throws Throwable {
// send down key and wait for idle
- getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
+ InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
// waiting for idle isn't always sufficient for the key to be fully processed
Thread.sleep(500);
}
- private void pollingCheckWebBackForwardList(final String currUrl, final int currIndex,
- final int size) {
+ private void pollingCheckWebBackForwardList(
+ final String currUrl, final int currIndex, final int size) {
new PollingCheck(WebkitUtils.TEST_TIMEOUT_MS) {
@Override
protected boolean check() {
@@ -2740,8 +2764,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}.run();
}
- private boolean checkWebBackForwardList(WebBackForwardList list, String currUrl,
- int currIndex, int size) {
+ private boolean checkWebBackForwardList(
+ WebBackForwardList list, String currUrl, int currIndex, int size) {
return (list != null)
&& (list.getSize() == size)
&& (list.getCurrentIndex() == currIndex)
@@ -2750,8 +2774,7 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
private void assertGoBackOrForwardBySteps(boolean expected, int steps) {
// skip if steps equals to 0
- if (steps == 0)
- return;
+ if (steps == 0) return;
int start = steps > 0 ? 1 : steps;
int end = steps > 0 ? steps : -1;
@@ -2770,15 +2793,14 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
private boolean isPictureFilledWithColor(Picture picture, int color) {
- if (picture.getWidth() == 0 || picture.getHeight() == 0)
- return false;
+ if (picture.getWidth() == 0 || picture.getHeight() == 0) return false;
- Bitmap bitmap = Bitmap.createBitmap(picture.getWidth(), picture.getHeight(),
- Config.ARGB_8888);
+ Bitmap bitmap =
+ Bitmap.createBitmap(picture.getWidth(), picture.getHeight(), Config.ARGB_8888);
picture.draw(new Canvas(bitmap));
- for (int i = 0; i < bitmap.getWidth(); i ++) {
- for (int j = 0; j < bitmap.getHeight(); j ++) {
+ for (int i = 0; i < bitmap.getWidth(); i++) {
+ for (int j = 0; j < bitmap.getHeight(); j++) {
if (color != bitmap.getPixel(i, j)) {
return false;
}
@@ -2788,14 +2810,13 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
/**
- * Waits at least MIN_SCROLL_WAIT_MS for scrolling to start. Once started,
- * scrolling is checked every SCROLL_WAIT_INTERVAL_MS for changes. Once
- * changes have stopped, the function exits. If no scrolling has happened
- * then the function exits after MIN_SCROLL_WAIT milliseconds.
+ * Waits at least MIN_SCROLL_WAIT_MS for scrolling to start. Once started, scrolling is checked
+ * every SCROLL_WAIT_INTERVAL_MS for changes. Once changes have stopped, the function exits. If
+ * no scrolling has happened then the function exits after MIN_SCROLL_WAIT milliseconds.
+ *
* @param previousScrollY The Y scroll position prior to waiting.
*/
- private void waitForScrollingComplete(int previousScrollY)
- throws InterruptedException {
+ private void waitForScrollingComplete(int previousScrollY) throws InterruptedException {
int scrollY = previousScrollY;
// wait at least MIN_SCROLL_WAIT for something to happen.
long noChangeMinWait = SystemClock.uptimeMillis() + MIN_SCROLL_WAIT_MS;
@@ -2817,11 +2838,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
* androidx.webkit.WebViewCompatTest#testGetSafeBrowsingPrivacyPolicyUrl. Modifications to this
* test should be reflected in that test as necessary. See http://go/modifying-webview-cts.
*/
+ @Test
public void testGetSafeBrowsingPrivacyPolicyUrl() throws Exception {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
assertNotNull(WebView.getSafeBrowsingPrivacyPolicyUrl());
try {
new URL(WebView.getSafeBrowsingPrivacyPolicyUrl().toString());
@@ -2830,11 +2848,8 @@ public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewCtsActi
}
}
+ @Test
public void testWebViewClassLoaderReturnsNonNull() {
- if (!NullWebViewUtils.isWebViewAvailable()) {
- return;
- }
-
assertNotNull(WebView.getWebViewClassLoader());
}
}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
index fad09f465bf..c0e5624b000 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -291,10 +291,8 @@ public class ConcurrencyTest extends WifiJUnit3TestBase {
|| state == NetworkInfo.DetailedState.DISCONNECTED) {
state = waitForNextNetworkState();
}
- if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
- if (state != NetworkInfo.DetailedState.CONNECTING) {
- return false;
- }
+ if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)
+ && state == NetworkInfo.DetailedState.CONNECTING) {
state = waitForNextNetworkState();
}
return state == NetworkInfo.DetailedState.CONNECTED;
diff --git a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 6205ee8806f..41cc640b30d 100644
--- a/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -562,7 +562,7 @@ public class WifiRttTest extends TestBase {
*/
@Test
public void testAwareRttWithPeerHandle() throws InterruptedException {
- if (WifiFeature.isAwareSupported(getContext())) {
+ if (!WifiFeature.isAwareSupported(getContext())) {
return;
}
PeerHandle peerHandle = mock(PeerHandle.class);
diff --git a/tests/uwb/Android.bp b/tests/uwb/Android.bp
index 94a4f506602..55e7ba628d2 100644
--- a/tests/uwb/Android.bp
+++ b/tests/uwb/Android.bp
@@ -36,6 +36,7 @@ android_test {
"mockito-target-minus-junit4",
"com.uwb.support.fira",
"com.uwb.support.multichip",
+ "com.uwb.support.oemextension",
],
srcs: ["src/**/*.java"],
platform_apis: true,
diff --git a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
index 097f799dbff..f10eb11d018 100644
--- a/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
+++ b/tests/uwb/src/android/uwb/cts/UwbManagerTest.java
@@ -26,10 +26,13 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.UiAutomation;
@@ -53,16 +56,24 @@ import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.modules.utils.build.SdkLevel;
+import com.google.uwb.support.fira.FiraControleeParams;
import com.google.uwb.support.fira.FiraOpenSessionParams;
import com.google.uwb.support.fira.FiraParams;
import com.google.uwb.support.fira.FiraProtocolVersion;
+import com.google.uwb.support.fira.FiraSpecificationParams;
import com.google.uwb.support.multichip.ChipInfoParams;
+import com.google.uwb.support.oemextension.DeviceStatus;
+import com.google.uwb.support.oemextension.RangingReportMetadata;
+import com.google.uwb.support.oemextension.SessionStatus;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
@@ -82,6 +93,9 @@ public class UwbManagerTest {
private final Context mContext = InstrumentationRegistry.getContext();
private UwbManager mUwbManager;
private String mDefaultChipId;
+ public static final int UWB_SESSION_STATE_IDLE = 0x03;
+ public static final byte DEVICE_STATE_ACTIVE = 0x02;
+ public static final int REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS = 0x00;
@Before
public void setup() throws Exception {
@@ -494,6 +508,16 @@ public class UwbManagerTest {
/* pass */
Log.i(TAG, "Failed with expected security exception: " + e);
}
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ mUwbManager.unregisterUwbVendorUciCallback(cb);
+ /* pass */
+ } catch (SecurityException e) {
+ /* fail */
+ fail();
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
}
@Test
@@ -525,6 +549,8 @@ public class UwbManagerTest {
public boolean onOpenFailedCalled;
public boolean onStartedCalled;
public boolean onStartFailedCalled;
+ public boolean onReconfiguredCalled;
+ public boolean onReconfiguredFailedCalled;
public boolean onClosedCalled;
public RangingSession rangingSession;
public RangingReport rangingReport;
@@ -566,9 +592,15 @@ public class UwbManagerTest {
mCtrlCountDownLatch.countDown();
}
- public void onReconfigured(@NonNull PersistableBundle params) { }
+ public void onReconfigured(@NonNull PersistableBundle params) {
+ onReconfiguredCalled = true;
+ mCtrlCountDownLatch.countDown();
+ }
- public void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params) { }
+ public void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params) {
+ onReconfiguredFailedCalled = true;
+ mCtrlCountDownLatch.countDown();
+ }
public void onStopped(@Reason int reason, @NonNull PersistableBundle parameters) { }
@@ -902,6 +934,107 @@ public class UwbManagerTest {
}
}
+ @Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
+ public void testFiraRangingSessionWithProvisionedSTS() throws Exception {
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+ // Needs UWB_PRIVILEGED permission which is held by shell.
+ uiAutomation.adoptShellPermissionIdentity();
+ CancellationSignal cancellationSignal = null;
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ CountDownLatch resultCountDownLatch = new CountDownLatch(1);
+ RangingSessionCallback rangingSessionCallback =
+ new RangingSessionCallback(countDownLatch, resultCountDownLatch);
+ PersistableBundle bundle = mUwbManager.getSpecificationInfo();
+ if (bundle.keySet().contains(FiraParams.PROTOCOL_NAME)) {
+ bundle = requireNonNull(bundle.getPersistableBundle(FiraParams.PROTOCOL_NAME));
+ }
+ FiraSpecificationParams params =
+ FiraSpecificationParams.fromBundle(bundle);
+ EnumSet<FiraParams.StsCapabilityFlag> stsCapabilities = EnumSet.of(
+ FiraParams.StsCapabilityFlag.HAS_STATIC_STS_SUPPORT,
+ FiraParams.StsCapabilityFlag.HAS_PROVISIONED_STS_SUPPORT);
+ assumeTrue(params.getStsCapabilities() == stsCapabilities);
+
+ FiraOpenSessionParams firaOpenSessionParams = new FiraOpenSessionParams.Builder()
+ .setProtocolVersion(new FiraProtocolVersion(1, 1))
+ .setSessionId(1)
+ .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED)
+ .setSessionKey(new byte[]{
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8
+ })
+ .setSubsessionKey(new byte[]{
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8,
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8
+ })
+ .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER)
+ .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR)
+ .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST)
+ .setDeviceAddress(UwbAddress.fromBytes(new byte[] {0x5, 6}))
+ .setDestAddressList(List.of(UwbAddress.fromBytes(new byte[] {0x5, 6})))
+ .build();
+ try {
+ // Needs UWB_PRIVILEGED & UWB_RANGING permission which is held by shell.
+ uiAutomation.adoptShellPermissionIdentity();
+ cancellationSignal = mUwbManager.openRangingSession(
+ firaOpenSessionParams.toBundle(),
+ Executors.newSingleThreadExecutor(),
+ rangingSessionCallback,
+ mDefaultChipId);
+ // Wait for the on opened callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.onOpenedCalled).isTrue();
+ assertThat(rangingSessionCallback.onOpenFailedCalled).isFalse();
+ assertThat(rangingSessionCallback.rangingSession).isNotNull();
+
+ countDownLatch = new CountDownLatch(1);
+ rangingSessionCallback.replaceCtrlCountDownLatch(countDownLatch);
+ rangingSessionCallback.rangingSession.start(new PersistableBundle());
+ // Wait for the on started callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.onStartedCalled).isTrue();
+ assertThat(rangingSessionCallback.onStartFailedCalled).isFalse();
+
+ countDownLatch = new CountDownLatch(1);
+ rangingSessionCallback.replaceCtrlCountDownLatch(countDownLatch);
+ UwbAddress uwbAddress = UwbAddress.fromBytes(new byte[] {0x5, 5});
+ rangingSessionCallback.rangingSession.addControlee(
+ new FiraControleeParams.Builder()
+ .setAddressList(new UwbAddress[] {uwbAddress})
+ .setSubSessionIdList(new int[] {1})
+ .build().toBundle()
+ );
+ // Wait for the on reconfigured callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.onReconfiguredCalled).isTrue();
+ assertThat(rangingSessionCallback.onReconfiguredFailedCalled).isFalse();
+
+ // Wait for the on ranging report callback.
+ assertThat(resultCountDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.rangingReport).isNotNull();
+
+ // Check the UWB state.
+ assertThat(mUwbManager.getAdapterState()).isEqualTo(STATE_ENABLED_ACTIVE);
+
+ // Stop ongoing session.
+ rangingSessionCallback.rangingSession.stop();
+ } finally {
+ if (cancellationSignal != null) {
+ countDownLatch = new CountDownLatch(1);
+ rangingSessionCallback.replaceCtrlCountDownLatch(countDownLatch);
+
+ // Close session.
+ cancellationSignal.cancel();
+
+ // Wait for the on closed callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.onClosedCalled).isTrue();
+ }
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
private class AdapterStateCallback implements UwbManager.AdapterStateCallback {
private final CountDownLatch mCountDownLatch;
private final @State Integer mWaitForState;
@@ -1011,4 +1144,207 @@ public class UwbManagerTest {
uiAutomation.dropShellPermissionIdentity();
}
}
+
+ private class UwbOemExtensionCallback implements UwbManager.UwbOemExtensionCallback {
+ public PersistableBundle mSessionChangeNtf;
+ public PersistableBundle mDeviceStatusNtf;
+ public PersistableBundle mSessionConfig;
+ public RangingReport mRangingReport;
+ public boolean onSessionConfigCompleteCalled = false;
+ public boolean onRangingReportReceivedCalled = false;
+ public boolean onSessionChangedCalled = false;
+ public boolean onDeviceStatusNtfCalled = false;
+
+ @Override
+ public void onSessionStatusNotificationReceived(
+ @NonNull PersistableBundle sessionStatusBundle) {
+ mSessionChangeNtf = sessionStatusBundle;
+ onSessionChangedCalled = true;
+ }
+
+ @Override
+ public void onDeviceStatusNotificationReceived(PersistableBundle deviceStatusBundle) {
+ mDeviceStatusNtf = deviceStatusBundle;
+ onDeviceStatusNtfCalled = true;
+ }
+
+ @NonNull
+ @Override
+ public int onSessionConfigurationComplete(@NonNull PersistableBundle openSessionBundle) {
+ mSessionConfig = openSessionBundle;
+ onSessionConfigCompleteCalled = true;
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public RangingReport onRangingReportReceived(
+ @NonNull RangingReport rangingReport) {
+ onRangingReportReceivedCalled = true;
+ mRangingReport = rangingReport;
+ return mRangingReport;
+ }
+ }
+
+ @Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2,C-1-5"})
+ public void testOemCallbackExtension() throws Exception {
+ Assume.assumeTrue(SdkLevel.isAtLeastU());
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+ CancellationSignal cancellationSignal = null;
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ CountDownLatch resultCountDownLatch = new CountDownLatch(1);
+ UwbOemExtensionCallback uwbOemExtensionCallback = new UwbOemExtensionCallback();
+
+ int sessionId = 1;
+ RangingSessionCallback rangingSessionCallback =
+ new RangingSessionCallback(countDownLatch, resultCountDownLatch);
+ FiraOpenSessionParams firaOpenSessionParams = new FiraOpenSessionParams.Builder()
+ .setProtocolVersion(new FiraProtocolVersion(1, 1))
+ .setSessionId(sessionId)
+ .setStsConfig(FiraParams.STS_CONFIG_STATIC)
+ .setVendorId(new byte[]{0x5, 0x6})
+ .setStaticStsIV(new byte[]{0x5, 0x6, 0x9, 0xa, 0x4, 0x6})
+ .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER)
+ .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR)
+ .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST)
+ .setDeviceAddress(UwbAddress.fromBytes(new byte[] {0x5, 6}))
+ .setDestAddressList(List.of(UwbAddress.fromBytes(new byte[] {0x5, 6})))
+ .build();
+ try {
+ // Needs UWB_PRIVILEGED & UWB_RANGING permission which is held by shell.
+ uiAutomation.adoptShellPermissionIdentity();
+ mUwbManager.registerUwbOemExtensionCallback(
+ Executors.newSingleThreadExecutor(), uwbOemExtensionCallback);
+ // Try to start a ranging session with invalid params, should fail.
+ cancellationSignal = mUwbManager.openRangingSession(
+ firaOpenSessionParams.toBundle(),
+ Executors.newSingleThreadExecutor(),
+ rangingSessionCallback,
+ mDefaultChipId);
+ // Wait for the on opened callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(uwbOemExtensionCallback.onSessionConfigCompleteCalled).isTrue();
+ assertThat(uwbOemExtensionCallback.mSessionConfig).isNotNull();
+
+ FiraOpenSessionParams openSessionParamsBundle = FiraOpenSessionParams
+ .fromBundle(uwbOemExtensionCallback.mSessionConfig);
+ assertEquals(openSessionParamsBundle.getSessionId(), sessionId);
+ assertEquals(openSessionParamsBundle.getStsConfig(), FiraParams.STS_CONFIG_STATIC);
+ assertEquals(openSessionParamsBundle.getDeviceType(),
+ FiraParams.RANGING_DEVICE_TYPE_CONTROLLER);
+
+ assertThat(uwbOemExtensionCallback.onSessionChangedCalled).isTrue();
+ assertThat(uwbOemExtensionCallback.mSessionChangeNtf).isNotNull();
+
+ SessionStatus sessionStatusBundle = SessionStatus
+ .fromBundle(uwbOemExtensionCallback.mSessionChangeNtf);
+ assertEquals(sessionStatusBundle.getSessionId(), sessionId);
+ assertEquals(sessionStatusBundle.getState(), UWB_SESSION_STATE_IDLE);
+ assertEquals(sessionStatusBundle.getReasonCode(),
+ REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS);
+
+ countDownLatch = new CountDownLatch(1);
+ rangingSessionCallback.replaceCtrlCountDownLatch(countDownLatch);
+ rangingSessionCallback.rangingSession.start(new PersistableBundle());
+ // Wait for the on started callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(uwbOemExtensionCallback.onSessionChangedCalled).isTrue();
+ assertThat(uwbOemExtensionCallback.mSessionChangeNtf).isNotNull();
+ assertThat(uwbOemExtensionCallback.onDeviceStatusNtfCalled).isTrue();
+ assertThat(uwbOemExtensionCallback.mDeviceStatusNtf).isNotNull();
+
+ DeviceStatus deviceStatusBundle = DeviceStatus
+ .fromBundle(uwbOemExtensionCallback.mDeviceStatusNtf);
+ assertEquals(deviceStatusBundle.getDeviceState(), DEVICE_STATE_ACTIVE);
+
+ // Wait for the on ranging report callback.
+ assertThat(resultCountDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.rangingReport).isNotNull();
+ assertThat(uwbOemExtensionCallback.onRangingReportReceivedCalled).isTrue();
+ assertThat(uwbOemExtensionCallback.mRangingReport).isNotNull();
+ PersistableBundle reportMetadataBundle = uwbOemExtensionCallback
+ .mRangingReport.getRangingReportMetadata();
+ RangingReportMetadata reportMetadata = RangingReportMetadata
+ .fromBundle(reportMetadataBundle);
+ assertEquals(reportMetadata.getSessionId(), sessionId);
+ assertThat(reportMetadata.getRawNtfData()).isNotEmpty();
+
+ // Check the UWB state.
+ assertThat(mUwbManager.getAdapterState()).isEqualTo(STATE_ENABLED_ACTIVE);
+
+ // Stop ongoing session.
+ rangingSessionCallback.rangingSession.stop();
+ } finally {
+ if (cancellationSignal != null) {
+ countDownLatch = new CountDownLatch(1);
+ rangingSessionCallback.replaceCtrlCountDownLatch(countDownLatch);
+
+ // Close session.
+ cancellationSignal.cancel();
+
+ // Wait for the on closed callback.
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
+ assertThat(rangingSessionCallback.onClosedCalled).isTrue();
+ }
+ try {
+ mUwbManager.unregisterUwbOemExtensionCallback(uwbOemExtensionCallback);
+ } catch (SecurityException e) {
+ /* pass */
+ fail();
+ }
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
+ public void testRegisterUwbOemExtensionCallbackWithoutUwbPrivileged() {
+ Assume.assumeTrue(SdkLevel.isAtLeastU());
+ UwbManager.UwbOemExtensionCallback cb = new UwbOemExtensionCallback();
+ try {
+ mUwbManager.registerUwbOemExtensionCallback(
+ Executors.newSingleThreadExecutor(), cb);
+ // should fail if the call was successful without UWB_PRIVILEGED permission.
+ fail();
+ } catch (SecurityException e) {
+ /* pass */
+ Log.i(TAG, "Failed with expected security exception: " + e);
+ }
+ }
+
+ @Test
+ @CddTest(requirements = {"7.3.13/C-1-1,C-1-2"})
+ public void testUnregisterUwbOemExtensionCallbackWithoutUwbPrivileged() {
+ Assume.assumeTrue(SdkLevel.isAtLeastU());
+ UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+ UwbManager.UwbOemExtensionCallback cb = new UwbOemExtensionCallback();
+ try {
+ // Needs UWB_PRIVILEGED & UWB_RANGING permission which is held by shell.
+ uiAutomation.adoptShellPermissionIdentity();
+ mUwbManager.registerUwbOemExtensionCallback(
+ Executors.newSingleThreadExecutor(), cb);
+ } catch (SecurityException e) {
+ /* fail */
+ fail();
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ try {
+ mUwbManager.unregisterUwbOemExtensionCallback(cb);
+ // should fail if the call was successful without UWB_PRIVILEGED permission.
+ fail();
+ } catch (SecurityException e) {
+ /* pass */
+ Log.i(TAG, "Failed with expected security exception: " + e);
+ }
+ try {
+ // Needs UWB_PRIVILEGED & UWB_RANGING permission which is held by shell.
+ uiAutomation.adoptShellPermissionIdentity();
+ mUwbManager.unregisterUwbOemExtensionCallback(cb);
+ } catch (SecurityException e) {
+ /* pass */
+ fail();
+ }
+ }
}
diff --git a/tests/uwb/src/android/uwb/cts/UwbTestUtils.java b/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
index 041b66c4337..a7689deec46 100644
--- a/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
+++ b/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
@@ -18,6 +18,7 @@ package android.uwb.cts;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.PersistableBundle;
import android.os.SystemClock;
import android.uwb.AngleMeasurement;
import android.uwb.AngleOfArrivalMeasurement;
@@ -63,6 +64,12 @@ public class UwbTestUtils {
return getRangingMeasurement(getUwbAddress(false));
}
+ public static PersistableBundle getTestRangingMetadata() {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putInt("TEST_KEY", 1);
+ return bundle;
+ }
+
public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
return new RangingMeasurement.Builder()
.setDistanceMeasurement(getDistanceMeasurement())
@@ -74,6 +81,7 @@ public class UwbTestUtils {
.setLineOfSight(RangingMeasurement.NLOS)
.setMeasurementFocus(RangingMeasurement.MEASUREMENT_FOCUS_RANGE)
.setRssiDbm(-85)
+ .setRangingMeasurementMetadata(getTestRangingMetadata())
.build();
}
diff --git a/tools/cts-media-preparer-app/Android.bp b/tools/cts-media-preparer-app/Android.bp
index cbad5684daa..7fe2a66ad1e 100644
--- a/tools/cts-media-preparer-app/Android.bp
+++ b/tools/cts-media-preparer-app/Android.bp
@@ -34,7 +34,7 @@ android_test {
test_suites: [
"cts",
"general-tests",
- "mts",
+ "mts-media",
],
sdk_version: "test_current",
min_sdk_version: "29",