summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-04 13:00:37 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-04 13:00:37 +0000
commit8452a2dd0eb390f16be0dd059aaf2664521baa80 (patch)
tree4773ffbfbbfe12a754da3f94dcee8518bad3eead
parent7c0087edcefdda138e14fd3e7b863353cc60de1a (diff)
parent377b4733b4a7316b25cc3d3272da002766578da3 (diff)
downloadcts-android13-mainline-media-release.tar.gz
Snap for 9689921 from 377b4733b4a7316b25cc3d3272da002766578da3 to mainline-media-releaseaml_med_331712010android13-mainline-media-release
Change-Id: I2796ca5c9f6bdcbb576d1dd77519b6e84c79711e
-rw-r--r--apps/CameraITS/tests/its_base_test.py35
-rw-r--r--hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java9
-rw-r--r--hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java97
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp24
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml31
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.pngbin0 -> 9670 bytes
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java126
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp33
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml27
-rw-r--r--hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java208
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java153
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java48
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java37
-rw-r--r--tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java21
-rw-r--r--tests/app/Android.bp1
-rw-r--r--tests/app/app/AndroidManifest.xml5
-rw-r--r--tests/app/app/src/android/app/stubs/RemoteActivity.java63
-rw-r--r--tests/app/src/android/app/cts/ActivityManagerTest.java123
-rw-r--r--[-rwxr-xr-x]tests/framework/base/windowmanager/app/AndroidManifest.xml2
-rw-r--r--tests/framework/base/windowmanager/app/res/values-watch/styles.xml26
-rw-r--r--tests/framework/base/windowmanager/app/res/values/styles.xml3
-rw-r--r--tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java6
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/CipherTest.java11
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java4
-rw-r--r--tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java9
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java71
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java61
-rw-r--r--tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java46
-rw-r--r--tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl1
-rw-r--r--tests/tests/security/src/android/security/cts/IsolatedProcessTest.java25
-rw-r--r--tests/tests/security/src/android/security/cts/IsolatedService.java9
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java7
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java36
-rw-r--r--tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java34
34 files changed, 1322 insertions, 70 deletions
diff --git a/apps/CameraITS/tests/its_base_test.py b/apps/CameraITS/tests/its_base_test.py
index 1a30ac293f2..5c8c95dfcc6 100644
--- a/apps/CameraITS/tests/its_base_test.py
+++ b/apps/CameraITS/tests/its_base_test.py
@@ -33,6 +33,14 @@ WAIT_TIME_SEC = 5
SCROLLER_TIMEOUT_MS = 3000
VALID_NUM_DEVICES = (1, 2)
NOT_YET_MANDATED_ALL = 100
+DEFAULT_TABLET_BRIGHTNESS = 192
+ELEVEN_BIT_TABLET_BRIGHTNESS = 1536
+ELEVEN_BIT_TABLET_NAMES = ('nabu',)
+LEGACY_TABLET_BRIGHTNESS = 96
+LEGACY_TABLET_NAME = 'dragon'
+TABLET_REQUIREMENTS_URL = 'https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-requirements'
+BRIGHTNESS_ERROR = ('Tablet brightness not set as per '
+ f'{TABLET_REQUIREMENTS_URL} in the config file')
# Not yet mandated tests ['test', first_api_level not yet mandatory]
# ie. ['test_test_patterns', 30] is MANDATED for first_api_level > 30
@@ -56,6 +64,27 @@ NOT_YET_MANDATED = {
logging.getLogger('matplotlib.font_manager').disabled = True
+def _validate_tablet_brightness(tablet_name, brightness):
+ """Ensures tablet brightness is set according to documentation.
+
+ https://source.android.com/docs/compatibility/cts/camera-its-box#tablet-requirements
+ Args:
+ tablet_name: tablet product name specified by `ro.build.product`.
+ brightness: brightness specified by config file.
+ """
+ name_to_brightness = {
+ LEGACY_TABLET_NAME: LEGACY_TABLET_BRIGHTNESS,
+ }
+ for name in ELEVEN_BIT_TABLET_NAMES:
+ name_to_brightness[name] = ELEVEN_BIT_TABLET_BRIGHTNESS
+ if tablet_name in name_to_brightness:
+ if brightness != name_to_brightness[tablet_name]:
+ raise AssertionError(BRIGHTNESS_ERROR)
+ else:
+ if brightness != DEFAULT_TABLET_BRIGHTNESS:
+ raise AssertionError(BRIGHTNESS_ERROR)
+
+
class ItsBaseTest(base_test.BaseTestClass):
"""Base test for CameraITS tests.
@@ -103,6 +132,12 @@ class ItsBaseTest(base_test.BaseTestClass):
try:
self.tablet = devices[1]
self.tablet_screen_brightness = self.user_params['brightness']
+ tablet_name_unencoded = self.tablet.adb.shell(
+ ['getprop', 'ro.build.product']
+ )
+ tablet_name = str(tablet_name_unencoded.decode('utf-8')).strip()
+ logging.debug('tablet name: %s', tablet_name)
+ _validate_tablet_brightness(tablet_name, self.tablet_screen_brightness)
except KeyError:
logging.debug('Not all tablet arguments set.')
else: # sensor_fusion or manual run
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index 94b83de6362..55e7dffc3fb 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -36,9 +36,11 @@ import android.app.UiAutomation;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
@@ -46,7 +48,7 @@ import android.support.test.uiautomator.UiObject2;
import android.util.Log;
import com.android.compatibility.common.util.PollingCheck;
-
+import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.devicepolicy.PermissionBroadcastReceiver;
import com.android.cts.devicepolicy.PermissionUtils;
@@ -105,6 +107,11 @@ public class PermissionsTest extends BaseDeviceAdminTest {
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PERMISSION_RESULT));
mDevice = UiDevice.getInstance(getInstrumentation());
mUiAutomation = getInstrumentation().getUiAutomation();
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
+ "safety_center_qs_tile_component_setting_flags",
+ Integer.toString(PackageManager.DONT_KILL_APP), false);
+ });
}
@Override
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java b/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java
new file mode 100644
index 00000000000..223ea2229cf
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Bug_261036568.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.Collections.singletonMap;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.NonRootSecurityTestCase;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Bug_261036568 extends NonRootSecurityTestCase {
+
+ private static final String TEST_PKG = "android.security.cts.BUG_261036568_test";
+
+ @Test
+ @AsbSecurityTest(cveBugId = 261036568)
+ public void testBug_261036568() {
+ ITestDevice device = null;
+ int newUser = -1;
+ try {
+ device = getDevice();
+ assumeTrue("Test requires multiple users", device.isMultiUserSupported());
+
+ newUser = device.createUser("CtsUser", /* guest */ true, /* ephemeral */ false);
+ assumeTrue("Unable to create test user", device.startUser(newUser, /* wait */ true));
+
+ installPackage("Bug-261036568-provider.apk", "--user " + newUser);
+ installPackage("Bug-261036568-test.apk");
+
+ Map<String, String> args = singletonMap("target_user", Integer.toString(newUser));
+ runDeviceTestsWithArgs(TEST_PKG, TEST_PKG + ".DeviceTest",
+ "testShareUnownedUriAsPreview", args);
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (newUser != -1) {
+ // Stop user 'CTSUser'
+ device.stopUser(newUser);
+
+ // Remove user 'CTSUser'
+ device.removeUser(newUser);
+ }
+ } catch (Exception e) {
+ CLog.e("failed to clean up guest user %d: %e", newUser, e);
+ }
+ }
+ }
+
+ private boolean runDeviceTestsWithArgs(String pkgName, String testClassName,
+ String testMethodName, Map<String, String> testArgs)
+ throws DeviceNotAvailableException {
+ final String testRunner = "androidx.test.runner.AndroidJUnitRunner";
+ final long defaultTestTimeoutMs = 60 * 1000L;
+ final long defaultMaxTimeoutToOutputMs = 60 * 1000L; // 1min
+ return runDeviceTests(getDevice(),
+ testRunner,
+ pkgName,
+ testClassName,
+ testMethodName,
+ /* userId */ null,
+ defaultTestTimeoutMs,
+ defaultMaxTimeoutToOutputMs,
+ /* maxInstrumentationTimeoutMillis */ 0L,
+ /* checkResults */ true,
+ /* isHiddenApiCheckDisabled */ false,
+ testArgs);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp
new file mode 100644
index 00000000000..d6d3022814e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "Bug-261036568-provider",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ asset_dirs: ["assets"],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml
new file mode 100644
index 00000000000..71e37a3431a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_261036568_provider">
+
+ <permission-tree android:name="com.android.cts"/>
+
+ <application
+ android:label="BUG-261036568-provider">>
+ <provider
+ android:name=".ImageProvider"
+ android:authorities="android.security.cts.BUG_261036568_provider"
+ android:enabled="true"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png
new file mode 100644
index 00000000000..8d17dab8f6f
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/assets/x.png
Binary files differ
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java
new file mode 100644
index 00000000000..667a0c098e7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/content-provider/src/android/security/cts/BUG_261036568_provider/ImageProvider.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_261036568_provider;
+
+import static android.os.Binder.getCallingUid;
+import static android.os.Binder.getCallingUserHandle;
+import static android.os.Process.myUid;
+import static android.os.Process.myUserHandle;
+import static android.provider.DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.provider.DocumentsContract;
+import android.provider.OpenableColumns;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ImageProvider extends ContentProvider {
+
+ private final Set<String> accessedUris = new HashSet<>();
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
+ maybeRecordUriAccess(uri);
+ try {
+ return getContext().getAssets().openFd("x.png");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) {
+ AssetFileDescriptor fd = openAssetFile(uri, mode);
+ return fd == null ? null : fd.getParcelFileDescriptor();
+ }
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ Bundle result = new Bundle();
+ if (method.equals("verify")) {
+ result.putBoolean("passed", accessedUris.isEmpty());
+ result.putStringArrayList("accessed_uris", new ArrayList<>(accessedUris));
+ accessedUris.clear();
+ }
+ return result;
+ }
+
+
+ @Override
+ public String getType(Uri uri) {
+ return uri.getPath().endsWith(".png") ? "image/png" : "*/*";
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ MatrixCursor cursor = new MatrixCursor(new String[] {
+ OpenableColumns.DISPLAY_NAME,
+ DocumentsContract.Root.COLUMN_TITLE,
+ DocumentsContract.Document.COLUMN_FLAGS
+ });
+ cursor.addRow(new Object[] {
+ "DISPLAY_NAME",
+ "TITLE",
+ FLAG_SUPPORTS_THUMBNAIL
+ });
+ return cursor;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ private void maybeRecordUriAccess(Uri uri) {
+ UserHandle caller = getCallingUserHandle();
+ if (!myUserHandle().equals(caller)) {
+ accessedUris.add("uri=" + uri.toString()
+ + ", owner_uid=" + myUid()
+ + ", caller_uid=" + getCallingUid()
+ + " ('" + getCallingPackage() + "')");
+ }
+ }
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp
new file mode 100644
index 00000000000..f7103aaf99c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "Bug-261036568-test",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
+ platform_apis: true,
+} \ No newline at end of file
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml
new file mode 100644
index 00000000000..c20ac2db0a1
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.BUG_261036568_test"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.BUG_261036568_test"/>
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java
new file mode 100644
index 00000000000..ab09be5f42e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/BUG-261036568/test-app/src/android/security/cts/BUG_261036568_test/DeviceTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.BUG_261036568_test;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.ClipData;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final long WAIT_AND_ASSERT_FOUND_TIMEOUT_MS = 5000;
+ private static final long WAIT_FOR_IDLE_TIMEOUT_MS = 5000;
+ private static final long WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS = 2500;
+
+ private static final String PROVIDER_AUTHORITY = "android.security.cts.BUG_261036568_provider";
+ private static final Uri PROVIDER_AUTHORITY_URI = Uri.parse("content://" + PROVIDER_AUTHORITY);
+
+ private ContentProviderClient mClient;
+ private Uri mTargetImageUri;
+ private Uri mTargetAuthorityUri;
+ private Uri mTargetFileUri;
+
+ @Before
+ public void setUp() {
+ Instrumentation instrumentation = getInstrumentation();
+ Context context = instrumentation.getContext();
+
+ // Get the id of a test user created by host side test
+ Bundle args = InstrumentationRegistry.getArguments();
+ int targetUser = Integer.parseInt(args.getString("target_user", "-1"));
+ assumeTrue("Could not find target user", targetUser != -1);
+
+ mTargetAuthorityUri = withUserId(PROVIDER_AUTHORITY_URI, targetUser);
+ mTargetImageUri = withPath(mTargetAuthorityUri, "x.png");
+ mTargetFileUri = withPath(mTargetAuthorityUri, "x.pdf");
+ }
+
+ @Test
+ public void testShareUnownedUriAsPreview() {
+ // SEND, single image
+ openAndCloseSharesheet(createSendImageIntent(mTargetImageUri));
+ // SEND, text with thumbnail
+ openAndCloseSharesheet(createSendTextIntentWithPreview(mTargetImageUri));
+ // SEND_MULTIPLE, two images
+ openAndCloseSharesheet(createSendFileIntentWithPreview(mTargetImageUri, mTargetImageUri));
+ // SEND_MULTIPLE, mixed types
+ openAndCloseSharesheet(createSendFileIntentWithPreview(mTargetImageUri, mTargetFileUri));
+
+ verifyNoContentProviderAccess();
+ }
+
+ private void openAndCloseSharesheet(Intent target) {
+ Instrumentation instrumentation = getInstrumentation();
+ UiDevice device = UiDevice.getInstance(instrumentation);
+ Context context = instrumentation.getTargetContext();
+ Intent chooserIntent = Intent.createChooser(target, null);
+ chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ String chooserPackage = resolveChooserPackage(context);
+ context.startActivity(chooserIntent);
+ device.waitForIdle(WAIT_FOR_IDLE_TIMEOUT_MS);
+ if (waitForPackageVisible(device, chooserPackage)) {
+ device.pressBack();
+ assumeTrue(waitForPackageGone(device, chooserPackage));
+ }
+ }
+
+ private void verifyNoContentProviderAccess() {
+ Instrumentation instrumentation = getInstrumentation();
+ Context context = instrumentation.getContext();
+ UiAutomation automation = instrumentation.getUiAutomation();
+ ContentResolver resolver = context.getContentResolver();
+
+ // only used for verification to access the provider directly
+ automation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+
+ try (ContentProviderClient client =
+ resolver.acquireContentProviderClient(mTargetAuthorityUri)) {
+ assumeNotNull("Could not access '" + mTargetAuthorityUri, client);
+
+ Bundle result = client.call("verify", null, null);
+ assumeNotNull("Failed to fetch result from content provider", result);
+
+ boolean passed = result.getBoolean("passed");
+ ArrayList<String> accessedUris = result.getStringArrayList("accessed_uris");
+ assertTrue("Failed. Cross user URI reads detected: " + accessedUris, passed);
+ } catch (RemoteException e) {
+ assumeNoException("Caught exception verifying result: " + e, e);
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+ }
+
+ private Intent createSendImageIntent(Uri image) {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, image);
+ sendIntent.setType("image/png");
+ return sendIntent;
+ }
+
+ private Intent createSendTextIntentWithPreview(Uri image) {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_TITLE, "Preview Title");
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "Sharing Text");
+ sendIntent.setType("text/plain");
+ sendIntent.setClipData(
+ new ClipData(
+ "Clip Label",
+ new String[] {"image/png"},
+ new ClipData.Item(image)));
+ return sendIntent;
+ }
+
+ private Intent createSendFileIntentWithPreview(Uri... uris) {
+ Intent sendIntent = new Intent();
+ if (uris.length > 1) {
+ sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
+ sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,
+ new ArrayList<>(Arrays.asList(uris)));
+ } else if (uris.length == 1) {
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_STREAM, uris[0]);
+ }
+ sendIntent.setType("application/pdf");
+ return sendIntent;
+ }
+
+ private String resolveChooserPackage(Context context) {
+ PackageManager pm = context.getPackageManager();
+ Intent shareIntent = Intent.createChooser(new Intent(), null);
+ ResolveInfo chooser = pm.resolveActivity(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ assertNotNull(chooser);
+ assertNotNull(chooser.activityInfo);
+ return chooser.activityInfo.packageName;
+ }
+
+ /**
+ * Same as waitAndAssertFound but searching the entire device UI.
+ */
+ private boolean waitForPackageVisible(UiDevice device, String pkg) {
+ return device.wait(
+ Until.findObject(By.pkg(pkg).depth(0)),
+ WAIT_AND_ASSERT_FOUND_TIMEOUT_MS
+ ) != null;
+ }
+
+ /**
+ * Same as waitAndAssertNotFound() but searching the entire device UI.
+ */
+ private boolean waitForPackageGone(UiDevice device, String pkg) {
+ return device.wait(Until.gone(By.pkg(pkg)), WAIT_AND_ASSERT_NOT_FOUND_TIMEOUT_MS);
+ }
+
+ private static Uri withUserId(Uri uri, int userId) {
+ Uri.Builder builder = uri.buildUpon();
+ builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
+ return builder.build();
+ }
+
+ private static Uri withPath(Uri uri, String path) {
+ return uri.buildUpon().appendPath(path).build();
+ }
+}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java
new file mode 100644
index 00000000000..e56c7233335
--- /dev/null
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBannersTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.photopicker.cts;
+
+import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvider;
+import static android.photopicker.cts.util.PhotoPickerFilesUtils.createImage;
+import static android.photopicker.cts.util.PhotoPickerFilesUtils.deleteMedia;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.SHORT_TIMEOUT;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.findBannerActionButton;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.findBannerDismissButton;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.getBannerPrimaryText;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.isPhotoPickerVisible;
+import static android.photopicker.cts.util.PhotoPickerUiUtils.verifySettingsActivityIsVisible;
+import static android.provider.MediaStore.ACTION_PICK_IMAGES;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.photopicker.cts.cloudproviders.CloudProviderPrimary;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.uiautomator.UiObject;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Photo Picker Banner Tests for common flows.
+ */
+// TODO(b/195009187): Enabling the banners requires setting allowed_cloud_providers device config.
+// We currently can't do this in R.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+public class PhotoPickerBannersTest extends PhotoPickerBaseTest {
+
+ private static String sPreviouslyAllowedCloudProviders;
+ private Uri mLocalMediaFileUri;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ // Store the current allowed cloud providers for reset at the end of tests.
+ sPreviouslyAllowedCloudProviders = PhotoPickerCloudUtils.getAllowedProvidersDeviceConfig();
+
+ // Override the allowed cloud providers config to enable the banners.
+ final String allowedCloudProviders = CloudProviderPrimary.AUTHORITY;
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(allowedCloudProviders);
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ // Reset the allowed cloud providers device config.
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(sPreviouslyAllowedCloudProviders);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ setCloudProvider(mContext, /* authority */ null);
+
+ // Create a local media file because if there's no media items for the picker grids,
+ // the recycler view gets hidden along with the banners.
+ mLocalMediaFileUri = createImage(mContext.getUserId(), /* isFavorite */ false).first;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+
+ deleteMedia(mLocalMediaFileUri, mContext);
+
+ setCloudProvider(mContext, /* authority */ null);
+ }
+
+ @Test
+ public void testChooseAppBannerOnDismiss() throws Exception {
+ // 1. Setting up the 'Choose App' banner.
+ setCloudMediaInfoForChooseAppBanner();
+
+ // 2. Assert that the 'Choose App' banner is visible.
+ assertThat(getBannerPrimaryText()).isEqualTo("Choose cloud media app");
+
+ // 3. Click the banner 'Dismiss' button.
+ final UiObject dismissButton = findBannerDismissButton();
+ dismissButton.click();
+
+ // 4. Assert that the Banner disappeared while the Picker is still visible.
+ assertWithMessage("Timed out waiting for the banner to disappear")
+ .that(dismissButton.waitUntilGone(SHORT_TIMEOUT))
+ .isTrue();
+ assertThatPhotoPickerActivityIsVisible();
+ }
+
+ @Test
+ public void testChooseAppBannerOnActionButtonClick() throws Exception {
+ // 1. Setting up the 'Choose App' banner.
+ setCloudMediaInfoForChooseAppBanner();
+
+ // 2. Assert that the 'Choose App' banner is visible.
+ assertThat(getBannerPrimaryText()).isEqualTo("Choose cloud media app");
+
+ // 3. Click the banner 'Action' button.
+ findBannerActionButton().click();
+
+ // 4. Assert that Settings page is visible.
+ verifySettingsActivityIsVisible();
+ sDevice.pressBack();
+ }
+
+ private void setCloudMediaInfoForChooseAppBanner() {
+ // 1. Set a non-null cloud provider and launch the photo picker.
+ setCloudProvider(mContext, CloudProviderPrimary.AUTHORITY);
+ launchPickerActivity();
+ // 2. Close the photo picker.
+ mActivity.finish();
+ // 3. Set the cloud provider as None and launch the photo picker.
+ setCloudProvider(mContext, /* authority */ null);
+ launchPickerActivity();
+ }
+
+ private void launchPickerActivity() {
+ final Intent intent = new Intent(ACTION_PICK_IMAGES);
+ mActivity.startActivity(intent);
+ assertThatPhotoPickerActivityIsVisible();
+ }
+
+ private void assertThatPhotoPickerActivityIsVisible() {
+ assertWithMessage("Timed out waiting for the photo picker activity to appear")
+ .that(isPhotoPickerVisible())
+ .isTrue();
+ }
+}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
index 96d3f933f03..59b552cdddf 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerCloudUtils.java
@@ -16,18 +16,26 @@
package android.photopicker.cts;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
import static android.photopicker.cts.PickerProviderMediaGenerator.setCloudProvider;
import static android.photopicker.cts.PickerProviderMediaGenerator.syncCloudProvider;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findAddButton;
import static android.photopicker.cts.util.PhotoPickerUiUtils.findItemList;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import android.app.UiAutomation;
import android.content.ClipData;
import android.content.Context;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
@@ -36,6 +44,9 @@ import java.util.Collections;
import java.util.List;
public class PhotoPickerCloudUtils {
+ private static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
+ private static final String ALLOWED_CLOUD_PROVIDERS_KEY = "allowed_cloud_providers";
+
public static List<String> extractMediaIds(ClipData clipData, int minCount) {
final int count = clipData.getItemCount();
assertThat(count).isAtLeast(minCount);
@@ -97,4 +108,41 @@ public class PhotoPickerCloudUtils {
assertThat(mediaIds).contains(contained);
assertThat(mediaIds).containsNoneIn(Collections.singletonList(notContained));
}
+
+ @Nullable
+ static String getAllowedProvidersDeviceConfig() {
+ getUiAutomation().adoptShellPermissionIdentity(READ_DEVICE_CONFIG);
+ try {
+ return DeviceConfig.getProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ ALLOWED_CLOUD_PROVIDERS_KEY);
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
+ }
+
+ static void setAllowedProvidersDeviceConfig(@Nullable String allowedCloudProviders) {
+ getUiAutomation().adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG);
+ try {
+ if (allowedCloudProviders == null) {
+ DeviceConfig.deleteProperty(NAMESPACE_STORAGE_NATIVE_BOOT,
+ ALLOWED_CLOUD_PROVIDERS_KEY);
+ assertWithMessage("Failed to delete the allowed cloud providers device config")
+ .that(getAllowedProvidersDeviceConfig())
+ .isNull();
+ } else {
+ DeviceConfig.setProperty(NAMESPACE_STORAGE_NATIVE_BOOT, ALLOWED_CLOUD_PROVIDERS_KEY,
+ allowedCloudProviders, /* makeDefault */ false);
+ assertWithMessage("Failed to update the allowed cloud providers device config")
+ .that(getAllowedProvidersDeviceConfig())
+ .isEqualTo(allowedCloudProviders);
+ }
+ } finally {
+ getUiAutomation().dropShellPermissionIdentity();
+ }
+ }
+
+ @NonNull
+ private static UiAutomation getUiAutomation() {
+ return InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
index f818c10baaf..d8cc456fe32 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerSettingsTest.java
@@ -36,8 +36,6 @@ import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
-import java.io.IOException;
-
/**
* Photo Picker tests for settings page launched from the overflow menu in PhotoPickerActivity or
* the Settings app.
@@ -47,37 +45,22 @@ import java.io.IOException;
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
public class PhotoPickerSettingsTest extends PhotoPickerBaseTest {
- private static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
- private static final String ALLOWED_CLOUD_PROVIDERS_KEY = "allowed_cloud_providers";
-
private static String sPreviouslyAllowedCloudProviders;
@BeforeClass
- public static void setUpBeforeClass() throws Exception {
+ public static void setUpBeforeClass() {
// Store current allowed cloud providers for reset at the end of tests.
- sPreviouslyAllowedCloudProviders = getAllowedProvidersDeviceConfig();
+ sPreviouslyAllowedCloudProviders = PhotoPickerCloudUtils.getAllowedProvidersDeviceConfig();
// Enable Settings menu item in PhotoPickerActivity's overflow menu.
- sDevice.executeShellCommand(
- String.format("device_config put %s %s not_empty", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- Assume.assumeTrue(!getAllowedProvidersDeviceConfig().isBlank());
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(
+ /* allowedCloudProviders */ "not_empty");
}
@AfterClass
- public static void tearDownClass() throws Exception {
+ public static void tearDownClass() {
// Reset allowed cloud providers device config.
- if (sPreviouslyAllowedCloudProviders == null
- || sPreviouslyAllowedCloudProviders.isBlank()) {
- // Delete the device config since `device_config put` does not support empty values.
- sDevice.executeShellCommand(
- String.format("device_config delete %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- } else {
- sDevice.executeShellCommand(
- String.format("device_config put %s %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY, sPreviouslyAllowedCloudProviders));
- }
+ PhotoPickerCloudUtils.setAllowedProvidersDeviceConfig(sPreviouslyAllowedCloudProviders);
}
@Test
@@ -93,16 +76,10 @@ public class PhotoPickerSettingsTest extends PhotoPickerBaseTest {
PhotoPickerUiUtils.clickAndWait(sDevice, settingsMenuItem);
// Verify PhotoPickerSettingsActivity is launched and visible.
- verifySettingsActivityIsVisible(sDevice);
+ verifySettingsActivityIsVisible();
verifySettingsActionBarIsVisible();
verifySettingsTitleIsVisible();
verifySettingsDescriptionIsVisible();
verifySettingsFragmentContainerExists();
}
-
- private static String getAllowedProvidersDeviceConfig() throws IOException {
- return sDevice.executeShellCommand(
- String.format("device_config get %s %s", NAMESPACE_STORAGE_NATIVE_BOOT,
- ALLOWED_CLOUD_PROVIDERS_KEY));
- }
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
index 85b0e89fefd..02e0b0cac48 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/util/PhotoPickerUiUtils.java
@@ -158,7 +158,7 @@ public class PhotoPickerUiUtils {
.isTrue();
}
- public static void verifySettingsActivityIsVisible(UiDevice uiDevice) {
+ public static void verifySettingsActivityIsVisible() {
// id/settings_activity_root is the root layout in activity_photo_picker_settings.xml
assertWithMessage("Timed out waiting for settings activity to appear")
.that(new UiObject(new UiSelector()
@@ -171,4 +171,23 @@ public class PhotoPickerUiUtils {
uiObject.click();
uiDevice.waitForIdle();
}
+
+ public static String getBannerPrimaryText() throws Exception {
+ final UiObject bannerPrimaryText = new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/banner_primary_text"));
+ assertWithMessage("Timed out waiting for the banner to appear")
+ .that(bannerPrimaryText.waitForExists(TIMEOUT))
+ .isTrue();
+ return bannerPrimaryText.getText();
+ }
+
+ public static UiObject findBannerDismissButton() {
+ return new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/dismiss_button"));
+ }
+
+ public static UiObject findBannerActionButton() {
+ return new UiObject(new UiSelector().resourceIdMatches(
+ REGEX_PACKAGE_NAME + ":id/action_button"));
+ }
}
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index 11bc2047c3f..a17e5104ff0 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -41,6 +41,7 @@ android_test {
srcs: [
"src/**/*.java",
"src/**/*.kt",
+ "app/src/android/app/stubs/RemoteActivity.java",
"NotificationListener/src/com/android/test/notificationlistener/INotificationUriAccessService.aidl",
],
// Tag this module as a cts test artifact
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index b78bb087c3f..7367ba98a2d 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -66,6 +66,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<application android:label="Android TestCase"
android:icon="@drawable/size_48x48"
@@ -591,6 +592,10 @@
</intent-filter>
</receiver>
+ <activity android:name="android.app.stubs.RemoteActivity"
+ android:process=":remote"
+ android:excludeFromRecents="true"
+ android:exported="true" />
</application>
</manifest>
diff --git a/tests/app/app/src/android/app/stubs/RemoteActivity.java b/tests/app/app/src/android/app/stubs/RemoteActivity.java
new file mode 100644
index 00000000000..0af1cbaf7cf
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/RemoteActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * An empty helper activity.
+ */
+public final class RemoteActivity extends Activity {
+
+ /** Extras to the launching intent */
+ public static final String EXTRA_CALLBACK = "callback";
+
+ private final IBinder mStub = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case IBinder.FIRST_CALL_TRANSACTION:
+ finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Intent intent = getIntent();
+ final IBinder callback = intent.getExtras().getBinder(EXTRA_CALLBACK);
+ final Parcel data = Parcel.obtain();
+ try {
+ data.writeStrongBinder(mStub);
+ callback.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
+ } catch (RemoteException e) {
+ } finally {
+ data.recycle();
+ }
+ }
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index e837f9a5f6f..3c69b092340 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -61,6 +61,7 @@ import android.app.stubs.CommandReceiver;
import android.app.stubs.LocalForegroundService;
import android.app.stubs.MockApplicationActivity;
import android.app.stubs.MockService;
+import android.app.stubs.RemoteActivity;
import android.app.stubs.ScreenOnActivity;
import android.app.stubs.TestHomeActivity;
import android.app.stubs.TrimMemService;
@@ -184,7 +185,7 @@ public class ActivityManagerTest {
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTargetContext = mInstrumentation.getTargetContext();
- mActivityManager = (ActivityManager) mInstrumentation.getContext()
+ mActivityManager = (ActivityManager) mTargetContext
.getSystemService(Context.ACTIVITY_SERVICE);
mPackageManager = mInstrumentation.getContext().getPackageManager();
mStartedActivityList = new ArrayList<Activity>();
@@ -192,6 +193,7 @@ public class ActivityManagerTest {
mAppStandbyEnabled = AppStandbyUtils.isAppStandbyEnabled();
mAutomotiveDevice = mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
mLeanbackOnly = mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
+ toggleScreenOn(true);
startSubActivity(ScreenOnActivity.class);
drainOrderedBroadcastQueue(2);
}
@@ -2310,4 +2312,123 @@ public class ActivityManagerTest {
return context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TELEVISION);
}
+
+ @Test
+ public void testKillBackgroundProcess() throws Exception {
+ final String otherPackage = "com.android.app1";
+ final ApplicationInfo ai1 = mTargetContext.getPackageManager()
+ .getApplicationInfo(otherPackage, 0);
+ final WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, Process.myUid(),
+ WAITFOR_MSEC);
+ final WatchUidRunner uid2Watcher = new WatchUidRunner(mInstrumentation, ai1.uid,
+ WAITFOR_MSEC);
+ try {
+ launchHome();
+
+ // Since we're running instrumentation, our proc state will stay above FGS.
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_FG_SERVICE);
+
+ // Start an activity in another process in our package, our proc state will goto TOP.
+ final CountDownLatch remoteBinderDeathLatch1 = startRemoteActivityAndLinkToDeath(
+ new ComponentName(mTargetContext, RemoteActivity.class),
+ uid1Watcher);
+
+ final CountDownLatch remoteBinderDeathLatch2 = startRemoteActivityAndLinkToDeath(
+ new ComponentName(otherPackage, STUB_PACKAGE_NAME + ".RemoteActivity"),
+ uid2Watcher);
+
+ // Launch home again so our activity will be backgrounded.
+ launchHome();
+
+ // The uid goes back to FGS state,
+ // but the process with the remote activity should have been in the background.
+ uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_FG_SERVICE);
+
+ // And the test package should be in background too.
+ uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE,
+ WatchUidRunner.STATE_LAST);
+
+ // Now, try to kill the background process of our own, it should succeed.
+ mActivityManager.killBackgroundProcesses(mTargetContext.getPackageName());
+
+ assertTrue("We should be able to kill our own process",
+ remoteBinderDeathLatch1.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+
+ // Try to kill the background process of other app, it should fail.
+ mActivityManager.killBackgroundProcesses(otherPackage);
+
+ assertFalse("We should be able to kill the processes of other package",
+ remoteBinderDeathLatch2.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+
+ // Adopt the permission, we should be able to kill it now.
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ android.Manifest.permission.FORCE_STOP_PACKAGES);
+
+ mActivityManager.killBackgroundProcesses(otherPackage);
+
+ assertTrue("We should be able to kill the processes of other package",
+ remoteBinderDeathLatch2.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+ } finally {
+ uid1Watcher.finish();
+ uid2Watcher.finish();
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+ finishAndRemoveTask(new ComponentName(mTargetContext, RemoteActivity.class));
+ }
+ }
+
+ private void finishAndRemoveTask(ComponentName activity) {
+ for (ActivityManager.AppTask task : mActivityManager.getAppTasks()) {
+ final ActivityManager.RecentTaskInfo info = task.getTaskInfo();
+ if (info != null && activity.equals(info.topActivity)) {
+ task.finishAndRemoveTask();
+ break;
+ }
+ }
+ }
+
+ private CountDownLatch startRemoteActivityAndLinkToDeath(ComponentName activity,
+ WatchUidRunner uidWatcher) throws Exception {
+ final IBinder[] remoteBinderHolder = new IBinder[1];
+ final CountDownLatch remoteBinderLatch = new CountDownLatch(1);
+ final IBinder binder = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case IBinder.FIRST_CALL_TRANSACTION:
+ remoteBinderHolder[0] = data.readStrongBinder();
+ remoteBinderLatch.countDown();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+ final CountDownLatch remoteBinderDeathLatch = new CountDownLatch(1);
+ final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ remoteBinderDeathLatch.countDown();
+ }
+ };
+ final Intent intent = new Intent();
+ intent.setComponent(activity);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Bundle extras = new Bundle();
+ extras.putBinder(RemoteActivity.EXTRA_CALLBACK, binder);
+ intent.putExtras(extras);
+ mTargetContext.startActivity(intent);
+
+ uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_TOP);
+ assertTrue("Failed to receive the callback from remote activity",
+ remoteBinderLatch.await(WAITFOR_MSEC, TimeUnit.MILLISECONDS));
+ assertNotNull(remoteBinderHolder[0]);
+ remoteBinderHolder[0].linkToDeath(recipient, 0);
+
+ // Sleep a while to let things go through.
+ Thread.sleep(WAIT_TIME);
+ return remoteBinderDeathLatch;
+ }
}
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 2e0a212502e..145e0cfcbd5 100755..100644
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -301,7 +301,7 @@
android:exported="true"/>
<activity android:name=".ShowWhenLockedDialogActivity"
android:exported="true"
- android:theme="@android:style/Theme.Material.Dialog"/>
+ android:theme="@style/ShowWhenLockedDialogTheme"/>
<activity android:name=".ShowWhenLockedTranslucentActivity"
android:exported="true"
android:theme="@android:style/Theme.Translucent"/>
diff --git a/tests/framework/base/windowmanager/app/res/values-watch/styles.xml b/tests/framework/base/windowmanager/app/res/values-watch/styles.xml
new file mode 100644
index 00000000000..14da3216ffc
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/res/values-watch/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="ShowWhenLockedDialogTheme" parent="@android:style/Theme.Material.Dialog">
+ <!-- Wear dialog theme has been converted to non-floating, but this breaks occluding -->
+ <item name="@android:windowIsFloating">true</item>
+ <!-- Likewise, for the purpose of CTS, make this non-swipeable, as there are visibility
+ implications there as well -->
+ <item name="@android:windowSwipeToDismiss">false</item>
+ </style>
+</resources>
diff --git a/tests/framework/base/windowmanager/app/res/values/styles.xml b/tests/framework/base/windowmanager/app/res/values/styles.xml
index 43f60ebe9a7..d0e35c0c053 100644
--- a/tests/framework/base/windowmanager/app/res/values/styles.xml
+++ b/tests/framework/base/windowmanager/app/res/values/styles.xml
@@ -101,4 +101,7 @@
<item name="android:windowLayoutInDisplayCutoutMode">always</item>
<item name="android:windowSoftInputMode">stateHidden</item>
</style>
+ <style name="ShowWhenLockedDialogTheme" parent="@android:style/Theme.Material.Dialog">
+ <!-- no-op except on Wear, where dialog theme has been converted to non-floating -->
+ </style>
</resources>
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
index f895e4f8a1a..f9211904bf4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
@@ -240,6 +240,9 @@ public class ActivityLifecyclePipTests extends ActivityLifecycleClientTestBase {
assertEmptySequence(PipActivity.class, getTransitionLog(),
"launchBelow");
+ // Set secondary split as launch root
+ mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
+
// Launch second activity to side
getTransitionLog().clear();
new Launcher(SecondActivity.class)
@@ -264,6 +267,9 @@ public class ActivityLifecyclePipTests extends ActivityLifecycleClientTestBase {
// Enter split screen
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
+ // Set secondary split as launch root
+ mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
+
// Launch second activity to side
final Activity secondActivity = new Launcher(SecondActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index e6de05385de..26b3658d974 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -616,16 +616,11 @@ public class CipherTest {
return (pm != null && pm.hasSystemFeature("android.software.leanback_only"));
}
- private boolean hasSecureLockScreen() {
- PackageManager pm = getContext().getPackageManager();
- return (pm != null && pm.hasSystemFeature("android.software.secure_lock_screen"));
- }
-
@Presubmit
@Test
public void testKeyguardLockAndUnlock()
throws Exception {
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
@@ -647,7 +642,7 @@ public class CipherTest {
final boolean isUnlockedDeviceRequired = true;
final boolean isUserAuthRequired = false;
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
@@ -1165,7 +1160,7 @@ public class CipherTest {
final boolean isUnlockedDeviceRequired = false;
final boolean isUserAuthRequired = true;
- if (!hasSecureLockScreen()) {
+ if (!TestUtils.hasSecureLockScreen(getContext())) {
return;
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 043b5de11cd..99e3d756ff4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -60,6 +60,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -494,6 +495,9 @@ public class KeyAttestationTest {
@Test
public void testEcAttestation_UniqueIdWorksWithCorrectPermission() throws Exception {
+ assumeTrue("Device doesn't have secure lock screen",
+ TestUtils.hasSecureLockScreen(getContext()));
+
String keystoreAlias = "test_key";
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
diff --git a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
index 84e8969007f..b965204fa76 100644
--- a/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/util/TestUtils.java
@@ -24,8 +24,8 @@ import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.SystemProperties;
import android.security.keystore.KeyGenParameterSpec;
@@ -55,6 +55,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
@@ -76,7 +77,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.security.SecureRandom;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@@ -1140,4 +1140,9 @@ public class TestUtils {
public static boolean isAttestationSupported() {
return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
}
+
+ public static boolean hasSecureLockScreen(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN));
+ }
}
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java
new file mode 100644
index 00000000000..4834cb3d621
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkMimeTypeMapTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkMimeTypeMapTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.MimeTypeMapTest");
+
+ @Test
+ public void testGetFileExtensionFromUrl() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetFileExtensionFromUrl");
+ }
+
+ @Test
+ public void testHasMimeType() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testHasMimeType");
+ }
+
+ @Test
+ public void testGetMimeTypeFromExtension() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetMimeTypeFromExtension");
+ }
+
+ @Test
+ public void testHasExtension() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testHasExtension");
+ }
+
+ @Test
+ public void testGetExtensionFromMimeType() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetExtensionFromMimeType");
+ }
+
+ @Test
+ public void testGetSingleton() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetSingleton");
+ }
+}
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java
new file mode 100644
index 00000000000..e83a333463e
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkServiceWorkerWebSettingsTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkServiceWorkerWebSettingsTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.ServiceWorkerWebSettingsTest");
+
+ @Test
+ public void testCacheMode() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testCacheMode");
+ }
+
+ @Test
+ public void testAllowContentAccess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testAllowContentAccess");
+ }
+
+ @Test
+ public void testAllowFileAccess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testAllowFileAccess");
+ }
+
+ @Test
+ public void testBlockNetworkLoads() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testBlockNetworkLoads");
+ }
+}
diff --git a/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java
new file mode 100644
index 00000000000..91f3fbedaec
--- /dev/null
+++ b/tests/tests/sdksandbox/webkit/src/android/sdksandbox/webkit/cts/SdkWebViewRenderProcessTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sdksandbox.webkit.cts;
+
+import android.app.sdksandbox.testutils.testscenario.KeepSdkSandboxAliveRule;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class SdkWebViewRenderProcessTest {
+ @ClassRule
+ public static final KeepSdkSandboxAliveRule sSdkTestSuiteSetup =
+ new KeepSdkSandboxAliveRule("com.android.emptysdkprovider");
+
+ @Rule
+ public final WebViewSandboxTestRule sdkTester =
+ new WebViewSandboxTestRule("android.webkit.cts.WebViewRenderProcessTest");
+
+ @Test
+ public void testGetWebViewRenderProcess() throws Exception {
+ sdkTester.assertSdkTestRunPasses("testGetWebViewRenderProcess");
+ }
+}
diff --git a/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
index 9c1a33985f3..4ed5e452d2b 100644
--- a/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
+++ b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
@@ -20,4 +20,5 @@ interface IIsolatedService {
String[] getCachedSystemServices();
IBinder getSystemService(String serviceName);
boolean getProcessIsIsolated();
+ void registerBroadcastReceiver();
}
diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
index 91e39e8a5fe..6bf5733b6db 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
@@ -15,6 +15,8 @@
*/
package android.security.cts;
+import static org.junit.Assert.assertThrows;
+
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
@@ -27,17 +29,23 @@ import android.platform.test.annotations.AsbSecurityTest;
import android.security.cts.IIsolatedService;
import android.security.cts.IsolatedService;
import android.util.Log;
+
import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.ArrayUtils;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+
import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.After;
-import androidx.test.runner.AndroidJUnit4;
-import org.junit.runner.RunWith;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
@RunWith(AndroidJUnit4.class)
public class IsolatedProcessTest {
@@ -112,6 +120,11 @@ public class IsolatedProcessTest {
Assert.assertTrue(mService.getProcessIsIsolated());
}
+ @Test
+ public void testRegisterBroadcastListener() throws RemoteException {
+ assertThrows(SecurityException.class, () -> mService.registerBroadcastReceiver());
+ }
+
@After
public void tearDown() {
getInstrumentation().getContext().unbindService(mServiceConnection);
diff --git a/tests/tests/security/src/android/security/cts/IsolatedService.java b/tests/tests/security/src/android/security/cts/IsolatedService.java
index 094f689a669..d77ef65ef31 100644
--- a/tests/tests/security/src/android/security/cts/IsolatedService.java
+++ b/tests/tests/security/src/android/security/cts/IsolatedService.java
@@ -18,9 +18,13 @@ package android.security.cts;
import android.app.Service;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
+
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -79,6 +83,11 @@ public class IsolatedService extends Service {
return Process.isIsolated();
}
+ public void registerBroadcastReceiver() throws SecurityException {
+ BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver(
+ getApplicationContext());
+ registerReceiver(receiver, new IntentFilter("testAction"));
+ }
};
@Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java b/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
index d112353ce19..b59d19c7878 100644
--- a/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/MimeTypeMapTest.java
@@ -33,7 +33,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class MimeTypeMapTest {
+public class MimeTypeMapTest extends SharedWebViewTest{
private MimeTypeMap mMimeTypeMap;
@@ -42,6 +42,11 @@ public class MimeTypeMapTest {
mMimeTypeMap = MimeTypeMap.getSingleton();
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ return new SharedWebViewTestEnvironment.Builder().build();
+ }
+
@Test
public void testGetFileExtensionFromUrl() {
assertEquals("html", MimeTypeMap.getFileExtensionFromUrl("http://localhost/index.html"));
diff --git a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
index 8b0c7228cf2..33ee18733a0 100644
--- a/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/ServiceWorkerWebSettingsTest.java
@@ -38,8 +38,7 @@ import org.junit.runner.RunWith;
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class ServiceWorkerWebSettingsTest {
-
+public class ServiceWorkerWebSettingsTest extends SharedWebViewTest {
private ServiceWorkerWebSettings mSettings;
private WebViewOnUiThread mOnUiThread;
@@ -49,14 +48,10 @@ public class ServiceWorkerWebSettingsTest {
@Before
public void setUp() throws Exception {
- Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
- mActivityScenarioRule.getScenario().onActivity(activity -> {
- WebViewCtsActivity webViewCtsActivity = (WebViewCtsActivity) activity;
- WebView webview = webViewCtsActivity.getWebView();
- if (webview != null) {
- mOnUiThread = new WebViewOnUiThread(webview);
- }
- });
+ WebView webview = getTestEnvironment().getWebView();
+ if (webview != null) {
+ mOnUiThread = new WebViewOnUiThread(webview);
+ }
mSettings = ServiceWorkerController.getInstance().getServiceWorkerWebSettings();
}
@@ -67,6 +62,27 @@ public class ServiceWorkerWebSettingsTest {
}
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
+
+ SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder();
+
+ mActivityScenarioRule
+ .getScenario()
+ .onActivity(
+ activity -> {
+ WebView webView = ((WebViewCtsActivity) activity).getWebView();
+ builder.setHostAppInvoker(
+ SharedWebViewTestEnvironment.createHostAppInvoker(
+ activity))
+ .setContext(activity)
+ .setWebView(webView);
+ });
+
+ return builder.build();
+ }
+
/**
* This should remain functionally equivalent to
* androidx.webkit.ServiceWorkerWebSettingsCompatTest#testCacheMode. Modifications to this test
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
index 288932421ea..5f5e1183ed4 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
@@ -48,7 +48,7 @@ import java.util.concurrent.Future;
@AppModeFull
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class WebViewRenderProcessTest {
+public class WebViewRenderProcessTest extends SharedWebViewTest {
private WebViewOnUiThread mOnUiThread;
@Rule
@@ -57,14 +57,10 @@ public class WebViewRenderProcessTest {
@Before
public void setUp() throws Exception {
- Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
- mActivityScenarioRule.getScenario().onActivity(activity -> {
- WebViewCtsActivity webViewCtsActivity = (WebViewCtsActivity) activity;
- WebView webview = webViewCtsActivity.getWebView();
- if (webview != null) {
- mOnUiThread = new WebViewOnUiThread(webview);
- }
- });
+ WebView webview = getTestEnvironment().getWebView();
+ if (webview != null) {
+ mOnUiThread = new WebViewOnUiThread(webview);
+ }
}
@After
@@ -74,6 +70,26 @@ public class WebViewRenderProcessTest {
}
}
+ @Override
+ protected SharedWebViewTestEnvironment createTestEnvironment() {
+ Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
+
+ SharedWebViewTestEnvironment.Builder builder = new SharedWebViewTestEnvironment.Builder();
+
+ mActivityScenarioRule
+ .getScenario()
+ .onActivity(
+ activity -> {
+ WebView webView = ((WebViewCtsActivity) activity).getWebView();
+ builder.setHostAppInvoker(
+ SharedWebViewTestEnvironment.createHostAppInvoker(
+ activity))
+ .setWebView(webView);
+ });
+
+ return builder.build();
+ }
+
private boolean terminateRenderProcessOnUiThread(
final WebViewRenderProcess renderer) {
return WebkitUtils.onMainThreadSync(() -> {