summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Elliot Sisteron <elliotsisteron@google.com> 2022-03-15 08:40:33 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-03-15 08:40:33 +0000
commite409677c8f5a5b63e96d7716d5830ec488eaec34 (patch)
treeb40f4fcad9261a7f78392ac4d1cb6c3b48e72015
parent7b3fde52decf298517bf5aaa3fb5e089b7c0caab (diff)
parenta0478e178790f26705ddb4db9c1300f45f9c091a (diff)
Merge "Disable SafetyCenter APIs if flag is off." into tm-dev
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java18
-rw-r--r--framework-s/java/android/safetycenter/SafetyCenterManager.java30
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataTracker.java39
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterService.java74
-rw-r--r--tests/cts/safetycenter/AndroidManifest.xml7
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt4
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt35
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt109
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt736
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt82
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt114
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt12
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/testing/AnyTester.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/testers/AnyTester.kt)2
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/testing/ParcelableTester.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt)2
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt156
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterFlags.kt55
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/testing/SafetySourceBroadcastReceiver.kt (renamed from tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt)47
19 files changed, 1038 insertions, 492 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
index 4b947aa26..64c52d1f0 100644
--- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterActivity.java
@@ -15,7 +15,13 @@
*/
package com.android.permissioncontroller.safetycenter.ui;
+import static android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT;
+
+import android.content.Intent;
import android.os.Bundle;
+import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
+import android.util.Log;
import androidx.annotation.Keep;
@@ -28,9 +34,21 @@ import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
@Keep
public final class SafetyCenterActivity extends CollapsingToolbarBaseActivity {
+ private static final String TAG = SafetyCenterActivity.class.getSimpleName();
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ SafetyCenterManager safetyCenterManager = getSystemService(SafetyCenterManager.class);
+
+ if (safetyCenterManager == null || !safetyCenterManager.isSafetyCenterEnabled()) {
+ Log.w(TAG, "Safety Center disabled, redirecting to security settings page");
+ startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS).addFlags(
+ FLAG_ACTIVITY_FORWARD_RESULT));
+ finish();
+ return;
+ }
+
setTitle(getString(R.string.safety_center_dashboard_page_title));
getSupportFragmentManager()
.beginTransaction()
diff --git a/framework-s/java/android/safetycenter/SafetyCenterManager.java b/framework-s/java/android/safetycenter/SafetyCenterManager.java
index fece3d543..11fc87403 100644
--- a/framework-s/java/android/safetycenter/SafetyCenterManager.java
+++ b/framework-s/java/android/safetycenter/SafetyCenterManager.java
@@ -133,7 +133,6 @@ public final class SafetyCenterManager {
/**
* Used as an {@code String} extra field in {@link #ACTION_REFRESH_SAFETY_SOURCES} intents to
* specify a string identifier for the broadcast.
- *
*/
public static final String EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID =
"android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID";
@@ -225,7 +224,8 @@ public final class SafetyCenterManager {
*
* @param errorDetails details of an error that should be displayed to the user
*/
- default void onError(@NonNull SafetyCenterErrorDetails errorDetails) {}
+ default void onError(@NonNull SafetyCenterErrorDetails errorDetails) {
+ }
}
private final Object mListenersLock = new Object();
@@ -249,7 +249,12 @@ public final class SafetyCenterManager {
this.mService = service;
}
- /** Returns whether the Safety Center feature is enabled. */
+ /**
+ * Returns whether the Safety Center feature is enabled.
+ *
+ * <p>If this returns {@code false}, all the other methods in this class will no-op and/or
+ * return default values.
+ */
@RequiresPermission(anyOf = {
READ_SAFETY_CENTER_STATUS,
SEND_SAFETY_CENTER_UPDATE
@@ -272,13 +277,13 @@ public final class SafetyCenterManager {
* <p>This call will rewrite any existing {@link SafetySourceData} already set for the given
* {@code safetySourceId} for the calling user.
*
- * @param safetySourceId the unique identifier for a safety source in the calling user
+ * @param safetySourceId the unique identifier for a safety source in the calling user
* @param safetySourceData the latest safety data for the safety source in the calling user. If
- * a safety source does not have any data to set, it can set its
- * {@link SafetySourceData} to {@code null}, in which case Safety Center
- * will fall back to any placeholder data specified in the safety source
- * xml configuration.
- * @param safetyEvent the event that triggered the safety source to set safety data
+ * a safety source does not have any data to set, it can set its
+ * {@link SafetySourceData} to {@code null}, in which case Safety Center
+ * will fall back to any placeholder data specified in the safety source
+ * xml configuration.
+ * @param safetyEvent the event that triggered the safety source to set safety data
*/
@RequiresPermission(SEND_SAFETY_CENTER_UPDATE)
public void setSafetySourceData(
@@ -328,7 +333,7 @@ public final class SafetyCenterManager {
* <p>Safety sources should use this API to notify Safety Center when Safety Center requested or
* expected them to perform an action or provide data, but they were unable to do so.
*
- * @param safetySourceId the id of the safety source that provided the issue
+ * @param safetySourceId the id of the safety source that provided the issue
* @param safetySourceErrorDetails details of the error that occurred
*/
@RequiresPermission(SEND_SAFETY_CENTER_UPDATE)
@@ -453,9 +458,10 @@ public final class SafetyCenterManager {
/**
* Executes the specified Safety Center issue action on the specified Safety Center issue.
*
- * @param safetyCenterIssueId the target issue ID returned by {@link SafetyCenterIssue#getId()}
+ * @param safetyCenterIssueId the target issue ID returned by
+ * {@link SafetyCenterIssue#getId()}
* @param safetyCenterIssueActionId the target action ID returned by {@link
- * SafetyCenterIssue.Action#getId()}
+ * SafetyCenterIssue.Action#getId()}
*/
@RequiresPermission(MANAGE_SAFETY_CENTER)
public void executeSafetyCenterIssueAction(
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
index e119ce6bd..b05246356 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java
@@ -91,7 +91,7 @@ final class SafetyCenterDataTracker {
@Nullable
SafetyCenterData setSafetySourceData(
@NonNull String safetySourceId,
- @NonNull SafetySourceData safetySourceData,
+ @Nullable SafetySourceData safetySourceData,
@NonNull String packageName,
@UserIdInt int userId) {
if (!configContains(safetySourceId, packageName)) {
@@ -101,7 +101,7 @@ final class SafetyCenterDataTracker {
Key key = Key.of(safetySourceId, packageName, userId);
SafetySourceData existingSafetySourceData = mSafetySourceDataForKey.get(key);
- if (safetySourceData.equals(existingSafetySourceData)) {
+ if (Objects.equals(safetySourceData, existingSafetySourceData)) {
return null;
}
@@ -152,6 +152,25 @@ final class SafetyCenterDataTracker {
return getSafetyCenterData(safetyCenterConfig, userId);
}
+ /**
+ * Returns a default {@link SafetyCenterData} object to be returned when the API is disabled.
+ */
+ @NonNull
+ static SafetyCenterData getDefaultSafetyCenterData() {
+ return new SafetyCenterData(
+ new SafetyCenterStatus.Builder()
+ .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .setTitle(getSafetyCenterStatusTitle(
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .setSummary(getSafetyCenterStatusSummary(
+ SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN))
+ .build(),
+ emptyList(),
+ emptyList(),
+ emptyList()
+ );
+ }
+
// TODO(b/219702252): Create a more efficient data structure for this, and update it when the
// config changes.
private boolean configContains(
@@ -479,22 +498,6 @@ final class SafetyCenterDataTracker {
}
}
- @NonNull
- private static SafetyCenterData getDefaultSafetyCenterData() {
- return new SafetyCenterData(
- new SafetyCenterStatus.Builder()
- .setSeverityLevel(SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN)
- .setTitle(getSafetyCenterStatusTitle(
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN))
- .setSummary(getSafetyCenterStatusSummary(
- SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN))
- .build(),
- emptyList(),
- emptyList(),
- emptyList()
- );
- }
-
@Nullable
private static SafetySourceStatus getSafetySourceStatus(
@Nullable SafetySourceData safetySourceData) {
diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java
index 3f6ff7be2..cea0ae404 100644
--- a/service/java/com/android/safetycenter/SafetyCenterService.java
+++ b/service/java/com/android/safetycenter/SafetyCenterService.java
@@ -45,6 +45,7 @@ import android.safetycenter.SafetySourceErrorDetails;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
+import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.RequiresApi;
@@ -111,17 +112,7 @@ public final class SafetyCenterService extends SystemService {
// TODO(b/214568975): Decide if we should disable safety center if there is a problem
// reading the config.
- // We don't require the caller to have READ_DEVICE_CONFIG permission.
- final long callingId = Binder.clearCallingIdentity();
- try {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* defaultValue = */ false)
- && getSafetyCenterConfigValue();
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
+ return isApiEnabled();
}
@Override
@@ -138,6 +129,9 @@ public final class SafetyCenterService extends SystemService {
// TODO(b/205706756): Security: check certs?
getContext().enforceCallingOrSelfPermission(SEND_SAFETY_CENTER_UPDATE,
"setSafetySourceData");
+ if (!checkApiEnabled("setSafetySourceData")) {
+ return;
+ }
// TODO(b/218812582): Validate the SafetySourceData.
SafetyCenterData safetyCenterData;
@@ -175,6 +169,9 @@ public final class SafetyCenterService extends SystemService {
// TODO(b/205706756): Security: check certs?
getContext().enforceCallingOrSelfPermission(
SEND_SAFETY_CENTER_UPDATE, "getSafetySourceData");
+ if (!checkApiEnabled("getSafetySourceData")) {
+ return null;
+ }
synchronized (mApiLock) {
return mSafetyCenterDataTracker.getSafetySourceData(safetySourceId, packageName,
@@ -194,6 +191,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "reportSafetySourceError", getContext());
getContext().enforceCallingOrSelfPermission(
SEND_SAFETY_CENTER_UPDATE, "reportSafetySourceError");
+ if (!checkApiEnabled("reportSafetySourceError")) {
+ return;
+ }
// TODO(b/218379298): Add implementation
}
@@ -206,6 +206,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "refreshSafetySources", getContext());
getContext().enforceCallingPermission(
MANAGE_SAFETY_CENTER, "refreshSafetySources");
+ if (!checkApiEnabled("refreshSafetySources")) {
+ return;
+ }
// We don't require the caller to have INTERACT_ACROSS_USERS and
// START_FOREGROUND_SERVICES_FROM_BACKGROUND permissions.
@@ -227,6 +230,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "getSafetyCenterData", getContext());
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "getSafetyCenterData");
+ if (!checkApiEnabled("getSafetyCenterData")) {
+ return SafetyCenterDataTracker.getDefaultSafetyCenterData();
+ }
synchronized (mApiLock) {
return mSafetyCenterDataTracker.getSafetyCenterData(userId);
@@ -242,6 +248,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "addOnSafetyCenterDataChangedListener", getContext());
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "addOnSafetyCenterDataChangedListener");
+ if (!checkApiEnabled("addOnSafetyCenterDataChangedListener")) {
+ return;
+ }
SafetyCenterData safetyCenterData;
synchronized (mApiLock) {
@@ -263,6 +272,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "removeOnSafetyCenterDataChangedListener", getContext());
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "removeOnSafetyCenterDataChangedListener");
+ if (!checkApiEnabled("removeOnSafetyCenterDataChangedListener")) {
+ return;
+ }
synchronized (mApiLock) {
mSafetyCenterListeners.removeListener(listener, userId);
@@ -276,6 +288,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "dismissSafetyCenterIssue", getContext());
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "dismissSafetyCenterIssue");
+ if (!checkApiEnabled("dismissSafetyCenterIssue")) {
+ return;
+ }
// TODO(b/202387059): Implement issue dismissal.
}
@@ -290,6 +305,9 @@ public final class SafetyCenterService extends SystemService {
userId, false, "executeSafetyCenterIssueAction", getContext());
getContext().enforceCallingOrSelfPermission(MANAGE_SAFETY_CENTER,
"executeSafetyCenterIssueAction");
+ if (!checkApiEnabled("executeSafetyCenterIssueAction")) {
+ return;
+ }
// TODO(b/218379298): Add implementation
}
@@ -297,6 +315,9 @@ public final class SafetyCenterService extends SystemService {
public void clearAllSafetySourceData() {
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "clearAllSafetySourceData");
+ if (!checkApiEnabled("clearAllSafetySourceData")) {
+ return;
+ }
synchronized (mApiLock) {
mSafetyCenterDataTracker.clear();
@@ -308,6 +329,9 @@ public final class SafetyCenterService extends SystemService {
@NonNull SafetyCenterConfig safetyCenterConfig) {
getContext().enforceCallingOrSelfPermission(MANAGE_SAFETY_CENTER,
"setSafetyCenterConfigOverride");
+ if (!checkApiEnabled("setSafetyCenterConfigOverride")) {
+ return;
+ }
synchronized (mRefreshLock) {
// TODO(b/217944317): Implement properly by overriding config in
@@ -335,6 +359,9 @@ public final class SafetyCenterService extends SystemService {
public void clearSafetyCenterConfigOverride() {
getContext().enforceCallingOrSelfPermission(
MANAGE_SAFETY_CENTER, "clearSafetyCenterConfigOverride");
+ if (!checkApiEnabled("clearSafetyCenterConfigOverride")) {
+ return;
+ }
synchronized (mRefreshLock) {
mSafetyCenterRefreshManager
@@ -342,6 +369,23 @@ public final class SafetyCenterService extends SystemService {
}
}
+ private boolean isApiEnabled() {
+ return getSafetyCenterConfigValue() && getDeviceConfigSafetyCenterEnabledProperty();
+ }
+
+ private boolean getDeviceConfigSafetyCenterEnabledProperty() {
+ // This call requires the READ_DEVICE_CONFIG permission.
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SAFETY_CENTER_ENABLED,
+ /* defaultValue = */ false);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
private boolean getSafetyCenterConfigValue() {
return getContext().getResources().getBoolean(Resources.getSystem().getIdentifier(
"config_enableSafetyCenter",
@@ -363,5 +407,13 @@ public final class SafetyCenterService extends SystemService {
throw new SecurityException(message + " requires any of: "
+ Arrays.toString(permissions) + ", but none were granted");
}
+
+ private boolean checkApiEnabled(@NonNull String message) {
+ if (!isApiEnabled()) {
+ Log.w(TAG, String.format("Called %s, but Safety Center is disabled", message));
+ return false;
+ }
+ return true;
+ }
}
}
diff --git a/tests/cts/safetycenter/AndroidManifest.xml b/tests/cts/safetycenter/AndroidManifest.xml
index cfa22f72b..4a784753b 100644
--- a/tests/cts/safetycenter/AndroidManifest.xml
+++ b/tests/cts/safetycenter/AndroidManifest.xml
@@ -18,13 +18,14 @@
package="android.safetycenter.cts">
<application>
- <uses-library android:name="android.test.runner"/>
-
- <receiver android:name=".SafetySourceBroadcastReceiver" android:exported="false">
+ <receiver android:name="android.safetycenter.testing.SafetySourceBroadcastReceiver"
+ android:exported="false">
<intent-filter>
<action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
</intent-filter>
</receiver>
+
+ <uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:label="CTS tests for SafetyCenter"
diff --git a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt
index 4c5723343..c42192ed8 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetyCenterConfigTest.kt
@@ -18,8 +18,8 @@ package android.safetycenter.config.cts
import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.config.SafetyCenterConfig
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
+import android.safetycenter.testing.AnyTester
+import android.safetycenter.testing.ParcelableTester
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
diff --git a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt
index f2a96df7d..9970dddf6 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourceTest.kt
@@ -19,8 +19,8 @@ package android.safetycenter.config.cts
import android.content.res.Resources
import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.config.SafetySource
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
+import android.safetycenter.testing.AnyTester
+import android.safetycenter.testing.ParcelableTester
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
diff --git a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt
index 2e61411bc..09c0de91f 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/config/cts/SafetySourcesGroupTest.kt
@@ -19,8 +19,8 @@ package android.safetycenter.config.cts
import android.content.res.Resources
import android.os.Build.VERSION_CODES.TIRAMISU
import android.safetycenter.config.SafetySourcesGroup
-import android.safetycenter.testers.AnyTester
-import android.safetycenter.testers.ParcelableTester
+import android.safetycenter.testing.AnyTester
+import android.safetycenter.testing.ParcelableTester
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
index 0adf45852..57a1c2c71 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterActivityTest.kt
@@ -20,11 +20,15 @@ import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_SAFETY_CENTER
import android.os.Build.VERSION_CODES.TIRAMISU
+import android.safetycenter.testing.SafetyCenterFlags
+import android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
import android.support.test.uiautomator.By
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,13 +37,36 @@ import org.junit.runner.RunWith
class SafetyCenterActivityTest {
private val context: Context = getApplicationContext()
+ @Before
+ fun assumeDeviceSupportsSafetyCenterToRunTests() {
+ assumeTrue(context.deviceSupportsSafetyCenter())
+ }
+
@Test
- fun launchActivity_showsSecurityAndPrivacyTitle() {
- context.startActivity(
- Intent(ACTION_SAFETY_CENTER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- )
+ fun launchActivity_withFlagEnabled_showsSecurityAndPrivacyTitle() {
+ SafetyCenterFlags.setSafetyCenterEnabled(true)
+
+ startSafetyCenterActivity()
// CollapsingToolbar title can't be found by text, so using description instead.
waitFindObject(By.desc("Security & Privacy"))
}
+
+ @Test
+ fun launchActivity_withFlagDisabled_showsSecurityTitle() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+
+ startSafetyCenterActivity()
+
+ // CollapsingToolbar title can't be found by text, so using description instead.
+ waitFindObject(By.desc("Security"))
+ }
+
+ private fun startSafetyCenterActivity() {
+ context.startActivity(
+ Intent(ACTION_SAFETY_CENTER)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ }
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt
deleted file mode 100644
index c3c7e7266..000000000
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterApisWithShellPermissions.kt
+++ /dev/null
@@ -1,109 +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.safetycenter.cts
-
-import android.Manifest.permission.MANAGE_SAFETY_CENTER
-import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
-import android.safetycenter.SafetyCenterData
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetyEvent
-import android.safetycenter.config.SafetyCenterConfig
-import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import java.util.concurrent.Executor
-
-/**
- * Call {@link SafetyCenterManager#setSafetySourceData} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId: String,
- safetySourceData: SafetySourceData,
- safetyEvent: SafetyEvent
-) =
- runWithShellPermissionIdentity({
- setSafetySourceData(safetySourceId, safetySourceData, safetyEvent)
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#getSafetySourceData} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.getSafetySourceDataWithPermission(id: String): SafetySourceData? =
- callWithShellPermissionIdentity({
- getSafetySourceData(id)
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#isSafetyCenterEnabled} adopting Shell's
- * {@link SEND_SAFETY_CENTER_UPDATE} permission.
- */
-fun SafetyCenterManager.isSafetyCenterEnabledWithPermission(): Boolean =
- callWithShellPermissionIdentity({
- isSafetyCenterEnabled
- }, SEND_SAFETY_CENTER_UPDATE)
-
-/**
- * Call {@link SafetyCenterManager#refreshSafetySources} adopting Shell's
- * {@link MANAGE_SAFETY_CENTER} permission (required for
- * {@link SafetyCenterManager#refreshSafetySources}).
- */
-fun SafetyCenterManager.refreshSafetySourcesWithPermission(refreshReason: Int) =
- runWithShellPermissionIdentity({
- refreshSafetySources(refreshReason)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.getSafetyCenterDataWithPermission(): SafetyCenterData =
- runWithShellPermissionIdentity(::getSafetyCenterData, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- executor: Executor,
- listener: OnSafetyCenterDataChangedListener
-) =
- runWithShellPermissionIdentity({
- addOnSafetyCenterDataChangedListener(executor, listener)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(
- listener: OnSafetyCenterDataChangedListener
-) =
- runWithShellPermissionIdentity({
- removeOnSafetyCenterDataChangedListener(listener)
- }, MANAGE_SAFETY_CENTER)
-
-/**
- * Call {@link SafetyCenterManager#clearAllSafetySourceData} adopting Shell's
- * {@link MANAGE_SAFETY_CENTER} permission.
- */
-fun SafetyCenterManager.clearAllSafetySourceDataWithPermission() =
- runWithShellPermissionIdentity({
- clearAllSafetySourceData()
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.setSafetyCenterConfigOverrideWithPermission(
- safetyCenterConfig: SafetyCenterConfig
-) =
- runWithShellPermissionIdentity({
- setSafetyCenterConfigOverride(safetyCenterConfig)
- }, MANAGE_SAFETY_CENTER)
-
-fun SafetyCenterManager.clearSafetyCenterConfigOverrideWithPermission() =
- runWithShellPermissionIdentity({
- clearSafetyCenterConfigOverride()
- }, MANAGE_SAFETY_CENTER)
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
index 0f29e9c46..a574a7892 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt
@@ -23,29 +23,45 @@ import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_SAFETY_CENTER
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
-import android.content.res.Resources
import android.os.Build.VERSION_CODES.TIRAMISU
-import android.provider.DeviceConfig
import android.safetycenter.SafetyCenterData
import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_PAGE_OPEN
import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK
-import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceIssue
+import android.safetycenter.SafetyCenterStatus
+import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceErrorDetails
+import android.safetycenter.SafetySourceIssue
import android.safetycenter.SafetySourceIssue.SEVERITY_LEVEL_CRITICAL_WARNING
import android.safetycenter.SafetySourceStatus
import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_CRITICAL_WARNING
+import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_NONE
+import android.safetycenter.SafetySourceStatus.STATUS_LEVEL_OK
import android.safetycenter.config.SafetyCenterConfig
import android.safetycenter.config.SafetySource
+import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC
import android.safetycenter.config.SafetySourcesGroup
+import android.safetycenter.testing.SafetyCenterFlags
+import android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import android.safetycenter.testing.SafetySourceBroadcastReceiver
+import android.safetycenter.testing.addOnSafetyCenterDataChangedListenerWithPermission
+import android.safetycenter.testing.clearAllSafetySourceDataWithPermission
+import android.safetycenter.testing.clearSafetyCenterConfigOverrideWithPermission
+import android.safetycenter.testing.getSafetyCenterDataWithPermission
+import android.safetycenter.testing.getSafetySourceDataWithPermission
+import android.safetycenter.testing.isSafetyCenterEnabledWithPermission
+import android.safetycenter.testing.refreshSafetySourcesWithPermission
+import android.safetycenter.testing.removeOnSafetyCenterDataChangedListenerWithPermission
+import android.safetycenter.testing.setSafetyCenterConfigOverrideWithPermission
+import android.safetycenter.testing.setSafetySourceDataWithPermission
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import kotlinx.coroutines.TimeoutCancellationException
@@ -53,6 +69,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.junit.After
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -64,293 +81,372 @@ import kotlin.test.assertFailsWith
class SafetyCenterManagerTest {
private val context: Context = getApplicationContext()
private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
- private val somePendingIntent = PendingIntent.getActivity(
- context, 0 /* requestCode */,
- Intent(ACTION_SAFETY_CENTER).addFlags(FLAG_ACTIVITY_NEW_TASK),
- FLAG_IMMUTABLE
- )
- private val safetySourceDataOnPageOpen = SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- "safetySourceDataOnPageOpen status title",
- "safetySourceDataOnPageOpen status summary",
- SafetySourceStatus.STATUS_LEVEL_NONE,
- somePendingIntent
- )
- .build()
+ private val somePendingIntent =
+ PendingIntent.getActivity(
+ context,
+ 0 /* requestCode */,
+ Intent(ACTION_SAFETY_CENTER),
+ FLAG_IMMUTABLE
)
- .build()
- private val safetySourceDataOnRescanClick = SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- "safetySourceDataOnRescanClick status title",
- "safetySourceDataOnRescanClick status summary",
- SafetySourceStatus.STATUS_LEVEL_RECOMMENDATION,
- somePendingIntent
+ private val safetySourceDataNone =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "None title",
+ "None summary",
+ STATUS_LEVEL_NONE,
+ somePendingIntent
+ )
+ .build()
)
- .build()
- ).build()
+ .build()
+ private val safetySourceDataOk =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder("Ok title", "Ok summary", STATUS_LEVEL_OK,
+ somePendingIntent)
+ .build()
+ )
+ .build()
+ private val safetySourceDataCritical =
+ SafetySourceData.Builder()
+ .setStatus(
+ SafetySourceStatus.Builder(
+ "Critical title",
+ "Critical summary",
+ STATUS_LEVEL_CRITICAL_WARNING,
+ somePendingIntent
+ )
+ .build()
+ )
+ .addIssue(
+ SafetySourceIssue.Builder(
+ "critical_issue_id",
+ "Critical issue title",
+ "Critical issue summary",
+ SEVERITY_LEVEL_CRITICAL_WARNING,
+ "issue_type_id"
+ )
+ .addAction(
+ SafetySourceIssue.Action.Builder("critical_action_id", "Solve issue",
+ somePendingIntent)
+ .build()
+ )
+ .build()
+ )
+ .build()
private val listenerChannel = Channel<SafetyCenterData>()
+
// The lambda has to be wrapped to the right type because kotlin wraps lambdas in a new Java
// functional interface implementation each time they are referenced/cast to a Java interface:
// b/215569072.
private val listener = OnSafetyCenterDataChangedListener {
- runBlockingWithTimeout {
- listenerChannel.send(it)
- }
+ runBlockingWithTimeout { listenerChannel.send(it) }
+ }
+
+ @Before
+ fun assumeDeviceSupportsSafetyCenterToRunTests() {
+ assumeTrue(context.deviceSupportsSafetyCenter())
}
@Before
@After
fun clearDataBetweenTest() {
+ SafetyCenterFlags.setSafetyCenterEnabled(true)
safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
safetyCenterManager.clearAllSafetySourceDataWithPermission()
+ safetyCenterManager.clearSafetyCenterConfigOverrideWithPermission()
SafetySourceBroadcastReceiver.reset()
}
- @Before
- fun setSafetyCenterConfigOverrideBeforeTest() {
- safetyCenterManager.clearSafetyCenterConfigOverrideWithPermission()
- // TODO(b/217944317): When the test API impl is finalized to override XML config, only
- // override config in select test cases that require it. This is to ensure that we do have
- // some test cases running with the XML config.
- safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_ONLY_CONFIG)
+ @After
+ fun cancelChannelAfterTest() {
+ listenerChannel.cancel()
}
- @After
- fun clearSafetyCenterConfigOverrideAfterTest() {
- safetyCenterManager.clearSafetyCenterConfigOverrideWithPermission()
+ @Test
+ fun isSafetyCenterEnabled_withFlagEnabled_returnsTrue() {
+ val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+
+ assertThat(isSafetyCenterEnabled).isTrue()
}
@Test
- fun getSafetySourceData_notSet_returnsNull() {
- val safetySourceData =
- safetyCenterManager.getSafetySourceDataWithPermission("some_unknown_id")
+ fun isSafetyCenterEnabled_withFlagDisabled_returnsFalse() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+
+ val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
- assertThat(safetySourceData).isNull()
+ assertThat(isSafetyCenterEnabled).isFalse()
+ }
+
+ @Test
+ fun isSafetyCenterEnabled_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.isSafetyCenterEnabled }
}
@Test
- fun setSafetySourceData_getSafetySourceDataReturnsNewValue() {
- val safetySourceData = SafetySourceData.Builder().build()
+ fun setSafetySourceData_validId_setsValue() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
)
- val safetySourceDataResult =
- safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
-
- assertThat(safetySourceDataResult).isEqualTo(safetySourceData)
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceDataNone)
}
@Test
- fun setSafetySourceData_withSameId_replacesValue() {
- val firstSafetySourceData = SafetySourceData.Builder().build()
+ fun setSafetySourceData_twice_replacesValue() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- firstSafetySourceData,
- EVENT_SOURCE_STATE_CHANGED
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
)
- val secondSafetySourceData = SafetySourceData.Builder().setStatus(
- SafetySourceStatus.Builder(
- "Status title", "Summary of the status", STATUS_LEVEL_CRITICAL_WARNING,
- somePendingIntent
- ).build()
- ).addIssue(
- SafetySourceIssue.Builder(
- "Issue id", "Issue title", "Summary of the issue",
- SEVERITY_LEVEL_CRITICAL_WARNING,
- "issue_type_id"
- )
- .addAction(
- SafetySourceIssue.Action.Builder(
- "action_id",
- "Solve issue",
- somePendingIntent
- ).build()
- ).build()
- ).build()
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- secondSafetySourceData,
- EVENT_SOURCE_STATE_CHANGED
+ CTS_SOURCE_ID,
+ safetySourceDataCritical,
+ EVENT_SOURCE_STATE_CHANGED
)
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
-
- assertThat(safetySourceData).isEqualTo(secondSafetySourceData)
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceDataCritical)
}
@Test
- fun isSafetyCenterEnabled_whenConfigEnabled_andFlagEnabled_returnsTrue() {
- if (!deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ true.toString(),
- /* makeDefault = */ false
- )
- }
+ fun setSafetySourceData_null_clearsValue() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
+ )
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceData = null,
+ EVENT_SOURCE_STATE_CHANGED
+ )
- assertThat(isSafetyCenterEnabled).isTrue()
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
}
@Test
- fun isSafetyCenterEnabled_whenConfigEnabled_andFlagDisabled_returnsFalse() {
- if (!deviceSupportsSafetyCenter()) {
- return
- }
+ fun setSafetySourceData_withFlagDisabled_noOp() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ false.toString(),
- /* makeDefault = */ false
- )
- }
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
+ )
- assertThat(isSafetyCenterEnabled).isFalse()
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
}
@Test
- fun isSafetyCenterEnabled_whenConfigDisabled_andFlagEnabled_returnsFalse() {
- if (deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ true.toString(),
- /* makeDefault = */ false
+ fun setSafetySourceData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.setSafetySourceData(
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
)
}
-
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
-
- assertThat(isSafetyCenterEnabled).isFalse()
}
@Test
- fun isSafetyCenterEnabled_whenConfigDisabled_andFlagDisabled_returnsFalse() {
- if (deviceSupportsSafetyCenter()) {
- return
- }
-
- runWithShellPermissionIdentity {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_CENTER_ENABLED,
- /* value = */ false.toString(),
- /* makeDefault = */ false
- )
- }
+ fun getSafetySourceData_validId_noData_returnsNull() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
- val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(isSafetyCenterEnabled).isFalse()
+ assertThat(apiSafetySourceData).isNull()
}
@Test
- fun isSafetyCenterEnabled_whenAppDoesNotHoldPermission_methodThrows() {
+ fun getSafetySourceData_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.isSafetyCenterEnabled
+ safetyCenterManager.getSafetySourceData(CTS_SOURCE_ID)
}
}
@Test
- fun refreshSafetySources_withoutManageSafetyCenterPermission_throwsSecurityException() {
+ fun reportSafetySourceError_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.refreshSafetySources(REFRESH_REASON_RESCAN_BUTTON_CLICK)
+ safetyCenterManager.reportSafetySourceError(
+ CTS_SOURCE_ID,
+ SafetySourceErrorDetails(EVENT_SOURCE_STATE_CHANGED)
+ )
}
}
@Test
- fun refreshSafetySources_whenReceiverDoesNotHaveSendingPermission_sourceDoesNotSendData() {
+ fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
+ SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataCritical
- safetyCenterManager.refreshSafetySourcesWithPermission(
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
REFRESH_REASON_RESCAN_BUTTON_CLICK
)
- assertFailsWith(TimeoutCancellationException::class) {
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_SHORT)
- }
- val safetySourceData =
+ val apiSafetySourceData =
safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isNull()
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceDataCritical)
}
@Test
- fun refreshSafetySources_withRefreshReasonRescanButtonClick_sourceSendsRescanData() {
+ fun refreshSafetySources_withRefreshReasonPageOpen_sourceSendsPageOpenData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
+ SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOk
safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_RESCAN_BUTTON_CLICK
- )
+ REFRESH_REASON_PAGE_OPEN)
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isEqualTo(safetySourceDataOnRescanClick)
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isEqualTo(safetySourceDataOk)
}
@Test
- fun refreshSafetySources_withRefreshReasonPageOpen_sourceSendsPageOpenData() {
+ fun refreshSafetySources_whenReceiverDoesNotHaveSendingPermission_sourceDoesNotSendData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOnPageOpen
+ SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataCritical
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- REFRESH_REASON_PAGE_OPEN
- )
+ safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK)
- val safetySourceData = safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
- assertThat(safetySourceData).isEqualTo(safetySourceDataOnPageOpen)
+ assertFailsWith(TimeoutCancellationException::class) {
+ SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_SHORT)
+ }
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
}
@Test
- fun refreshSafetySources_withInvalidRefreshSeason_throwsIllegalArgumentException() {
+ fun refreshSafetySources_withFlagDisabled_noOp() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
SafetySourceBroadcastReceiver.safetySourceId = CTS_SOURCE_ID
- SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOnPageOpen
- SafetySourceBroadcastReceiver.safetySourceDataOnRescanClick = safetySourceDataOnRescanClick
+ SafetySourceBroadcastReceiver.safetySourceDataOnPageOpen = safetySourceDataOk
- assertFailsWith(IllegalArgumentException::class) {
- safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(500)
+ assertFailsWith(TimeoutCancellationException::class) {
+ safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
+ REFRESH_REASON_PAGE_OPEN, TIMEOUT_SHORT)
}
+ val apiSafetySourceData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ assertThat(apiSafetySourceData).isNull()
}
@Test
- fun getSafetyCenterData_returnsSafetyCenterData() {
- val safetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
-
- // TODO(b/218830137): Assert on content.
- assertThat(safetyCenterData).isNotNull()
+ fun refreshSafetySources_withInvalidRefreshSeason_throwsIllegalArgumentException() {
+ val thrown =
+ assertFailsWith(IllegalArgumentException::class) {
+ safetyCenterManager.refreshSafetySourcesWithPermission(500)
+ }
+ assertThat(thrown).hasMessageThat().isEqualTo("Invalid refresh reason: 500")
}
@Test
- fun getSafetyCenterData_whenAppDoesNotHoldPermission_methodThrows() {
+ fun refreshSafetySources_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.safetyCenterData
+ safetyCenterManager.refreshSafetySources(REFRESH_REASON_RESCAN_BUTTON_CLICK)
}
}
@Test
- fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterData() {
+ fun getSafetyCenterData_withoutDataProvided_returnsDataFromConfig() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ // TODO(b/218830137): Assert on content.
+ assertThat(apiSafetyCenterData).isNotNull()
+ }
+
+ @Test
+ fun getSafetyCenterData_withSomeDataProvided_returnsDataProvided() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataNone,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ // TODO(b/218830137): Assert on content.
+ assertThat(apiSafetyCenterData).isNotNull()
+ }
+
+ @Test
+ fun getSafetyCenterData_withUpdatedData_returnsUpdatedData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val previousApiSafetyCenterData =
+ safetyCenterManager.getSafetySourceDataWithPermission(CTS_SOURCE_ID)
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataCritical,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ // TODO(b/218830137): Assert on content.
+ assertThat(apiSafetyCenterData).isNotEqualTo(previousApiSafetyCenterData)
+ }
+
+ @Test
+ fun getSafetyCenterData_withFlagDisabled_returnsDefaultData() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+
+ val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
+
+ assertThat(apiSafetyCenterData).isEqualTo(SafetyCenterData(
+ SafetyCenterStatus.Builder()
+ .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
+ .setTitle("Unknown")
+ .setSummary("Unknown safety status")
+ .build(),
+ emptyList(),
+ emptyList(),
+ emptyList()
+ ))
+ }
+
+ @Test
+ fun getSafetyCenterData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.safetyCenterData }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWithSafetyCenterDataFromConfig() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
+ directExecutor(),
+ listener
)
val safetyCenterDataFromListener = receiveListenerUpdate()
@@ -360,17 +456,18 @@ class SafetyCenterManagerTest {
@Test
fun addOnSafetyCenterDataChangedListener_listenerCalledOnSafetySourceData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
+ directExecutor(),
+ listener
)
// Receive initial data.
receiveListenerUpdate()
- val safetySourceData = SafetySourceData.Builder().build()
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
)
val safetyCenterDataFromListener = receiveListenerUpdate()
@@ -379,19 +476,75 @@ class SafetyCenterManagerTest {
}
@Test
- fun removeOnSafetyCenterDataChangedListener_listenerNotCalledOnSafetySourceData() {
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataChanges() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
+ directExecutor(),
+ listener
)
// Receive initial data.
receiveListenerUpdate()
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ // Receive update from #setSafetySourceData call.
+ receiveListenerUpdate()
- safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
- val safetySourceData = SafetySourceData.Builder().build()
safetyCenterManager.setSafetySourceDataWithPermission(
- CTS_SOURCE_ID,
- safetySourceData,
- EVENT_SOURCE_STATE_CHANGED
+ CTS_SOURCE_ID,
+ safetySourceDataCritical,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val safetyCenterDataFromListener = receiveListenerUpdate()
+
+ // TODO(b/218830137): Assert on content.
+ assertThat(safetyCenterDataFromListener).isNotNull()
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerCalledWhenSafetySourceDataCleared() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+ // Receive initial data.
+ receiveListenerUpdate()
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ // Receive update from #setSafetySourceData call.
+ receiveListenerUpdate()
+
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceData = null,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ val safetyCenterDataFromListener = receiveListenerUpdate()
+
+ // TODO(b/218830137): Assert on content.
+ assertThat(safetyCenterDataFromListener).isNotNull()
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataStaysNull() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+ // Receive initial data.
+ receiveListenerUpdate()
+
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceData = null,
+ EVENT_SOURCE_STATE_CHANGED
)
assertFailsWith(TimeoutCancellationException::class) {
@@ -400,18 +553,102 @@ class SafetyCenterManagerTest {
}
@Test
- fun addOnSafetyCenterDataChangedListener_whenAppDoesNotHoldPermission_methodThrows() {
+ fun addOnSafetyCenterDataChangedListener_listenerNotCalledWhenSafetySourceDataDoesntChange() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+ // Receive initial data.
+ receiveListenerUpdate()
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+ // Receive update from #setSafetySourceData call.
+ receiveListenerUpdate()
+
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ receiveListenerUpdate(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_withFlagDisabled_listenerNotCalled() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ receiveListenerUpdate(TIMEOUT_SHORT)
+ }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
- safetyCenterManager.addOnSafetyCenterDataChangedListener(
- directExecutor(), listener
- )
+ safetyCenterManager.addOnSafetyCenterDataChangedListener(directExecutor(), listener)
+ }
+ }
+
+ @Test
+ fun addOnSafetyCenterDataChangedListener_oneShot_doesntDeadlock() {
+ val oneShotListener =
+ object : OnSafetyCenterDataChangedListener {
+ override fun onSafetyCenterDataChanged(safetyCenterData: SafetyCenterData) {
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(this)
+ runBlockingWithTimeout { listenerChannel.send(safetyCenterData) }
+ }
+ }
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ oneShotListener
+ )
+
+ // Check that we don't deadlock when using a one-shot listener: this is because adding the
+ // listener could call the listener while holding a lock on the binder thread-pool; causing
+ // a deadlock when attempting to call the `SafetyCenterManager` from that listener.
+ receiveListenerUpdate()
+ }
+
+ @Test
+ fun removeOnSafetyCenterDataChangedListener_listenerNotCalledOnSafetySourceData() {
+ safetyCenterManager.setSafetyCenterConfigOverrideWithPermission(CTS_CONFIG)
+ safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ directExecutor(),
+ listener
+ )
+ // Receive initial data.
+ receiveListenerUpdate()
+
+ safetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(listener)
+ safetyCenterManager.setSafetySourceDataWithPermission(
+ CTS_SOURCE_ID,
+ safetySourceDataOk,
+ EVENT_SOURCE_STATE_CHANGED
+ )
+
+ assertFailsWith(TimeoutCancellationException::class) {
+ receiveListenerUpdate(TIMEOUT_SHORT)
}
}
@Test
- fun removeOnSafetyCenterDataChangedListener_whenAppDoesNotHoldPermission_methodThrows() {
+ fun removeOnSafetyCenterDataChangedListener_withoutPermission_throwsSecurityException() {
safetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
- directExecutor(), listener
+ directExecutor(),
+ listener
)
assertFailsWith(SecurityException::class) {
@@ -420,79 +657,94 @@ class SafetyCenterManagerTest {
}
@Test
- fun dismissSafetyCenterIssue_whenAppDoesNotHoldPermission_methodThrows() {
+ fun dismissSafetyCenterIssue_withoutPermission_throwsSecurityException() {
assertFailsWith(SecurityException::class) {
safetyCenterManager.dismissSafetyCenterIssue("bleh")
}
}
- private fun deviceSupportsSafetyCenter() =
- context.resources.getBoolean(
- Resources.getSystem().getIdentifier(
- "config_enableSafetyCenter",
- "bool",
- "android"
- )
- )
+ @Test
+ fun executeSafetyCenterIssueAction_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.executeSafetyCenterIssueAction("bleh", "blah")
+ }
+ }
+
+ @Test
+ fun clearAllSafetySourceData_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) { safetyCenterManager.clearAllSafetySourceData() }
+ }
+
+ @Test
+ fun setSafetyCenterConfigOverride_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.setSafetyCenterConfigOverride(CTS_CONFIG)
+ }
+ }
+
+ @Test
+ fun clearSafetyCenterConfigOverride_withoutPermission_throwsSecurityException() {
+ assertFailsWith(SecurityException::class) {
+ safetyCenterManager.clearSafetyCenterConfigOverride()
+ }
+ }
private fun SafetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(
- refreshReason: Int
+ refreshReason: Int,
+ timeout: Duration = TIMEOUT_LONG
) {
- try {
- runWithShellPermissionIdentity({
+ callWithShellPermissionIdentity(
+ {
refreshSafetySources(refreshReason)
- SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(TIMEOUT_LONG)
- }, SEND_SAFETY_CENTER_UPDATE, MANAGE_SAFETY_CENTER)
- } catch (e: RuntimeException) {
- throw e.cause ?: e
- }
+ SafetySourceBroadcastReceiver.waitTillOnReceiveComplete(timeout)
+ },
+ SEND_SAFETY_CENTER_UPDATE,
+ MANAGE_SAFETY_CENTER
+ )
}
private fun receiveListenerUpdate(timeout: Duration = TIMEOUT_LONG): SafetyCenterData =
- runBlockingWithTimeout(timeout) {
- listenerChannel.receive()
- }
+ runBlockingWithTimeout(timeout) { listenerChannel.receive() }
private fun <T> runBlockingWithTimeout(
timeout: Duration = TIMEOUT_LONG,
block: suspend () -> T
) =
runBlocking {
- withTimeout(timeout.toMillis()) {
- block()
- }
+ withTimeout(timeout.toMillis()) { block() }
}
companion object {
- /** Name of the flag that determines whether SafetyCenter is enabled. */
- private const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
private const val CTS_PACKAGE_NAME = "android.safetycenter.cts"
private const val CTS_BROADCAST_RECEIVER_NAME =
- "android.safetycenter.cts.SafetySourceBroadcastReceiver"
+ "android.safetycenter.testing.SafetySourceBroadcastReceiver"
private val TIMEOUT_LONG: Duration = Duration.ofMillis(5000)
private val TIMEOUT_SHORT: Duration = Duration.ofMillis(1000)
private val EVENT_SOURCE_STATE_CHANGED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
private const val CTS_SOURCE_ID = "cts_source_id"
+ private const val CTS_SOURCE_GROUP_ID = "cts_source_group"
+
// TODO(b/217944317): Consider moving the following to a file where they can be used by
// other tests.
- private val CTS_SOURCE = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC)
+ private val CTS_SOURCE =
+ SafetySource.Builder(SAFETY_SOURCE_TYPE_DYNAMIC)
.setId(CTS_SOURCE_ID)
.setPackageName(CTS_PACKAGE_NAME)
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
- .setIntentAction("SafetyCenterManagerTest.INTENT_ACTION")
+ .setTitleResId(android.R.string.ok)
+ .setSummaryResId(android.R.string.ok)
+ .setIntentAction(ACTION_SAFETY_CENTER)
.setBroadcastReceiverClassName(CTS_BROADCAST_RECEIVER_NAME)
.setProfile(SafetySource.PROFILE_PRIMARY)
.build()
- private val CTS_SOURCE_GROUP = SafetySourcesGroup.Builder()
- .setId("cts_source_group")
- .setTitleResId(R.string.reference)
- .setSummaryResId(R.string.reference)
+ private val CTS_SOURCE_GROUP =
+ SafetySourcesGroup.Builder()
+ .setId(CTS_SOURCE_GROUP_ID)
+ .setTitleResId(android.R.string.ok)
+ .setSummaryResId(android.R.string.ok)
.addSafetySource(CTS_SOURCE)
.build()
- private val CTS_ONLY_CONFIG = SafetyCenterConfig.Builder()
- .addSafetySourcesGroup(CTS_SOURCE_GROUP)
- .build()
+ private val CTS_CONFIG =
+ SafetyCenterConfig.Builder().addSafetySourcesGroup(CTS_SOURCE_GROUP).build()
}
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
new file mode 100644
index 000000000..5265a4fab
--- /dev/null
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterUnsupportedTest.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.safetycenter.cts
+
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SAFETY_CENTER
+import android.os.Build.VERSION_CODES.TIRAMISU
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.testing.SafetyCenterFlags
+import android.safetycenter.testing.SafetyCenterFlags.deviceSupportsSafetyCenter
+import android.safetycenter.testing.isSafetyCenterEnabledWithPermission
+import android.support.test.uiautomator.By
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = TIRAMISU, codeName = "Tiramisu")
+class SafetyCenterUnsupportedTest {
+ private val context: Context = getApplicationContext()
+ private val safetyCenterManager = context.getSystemService(SafetyCenterManager::class.java)!!
+
+ @Before
+ fun assumeDeviceDoesntSupportSafetyCenterToRunTests() {
+ assumeFalse(context.deviceSupportsSafetyCenter())
+ }
+
+ @Test
+ fun launchActivity_showsSecurityTitle() {
+ startSafetyCenterActivity()
+
+ // CollapsingToolbar title can't be found by text, so using description instead.
+ waitFindObject(By.desc("Security"))
+ }
+
+ @Test
+ fun isSafetyCenterEnabled_withFlagEnabled_returnsFalse() {
+ SafetyCenterFlags.setSafetyCenterEnabled(true)
+
+ val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+
+ assertThat(isSafetyCenterEnabled).isFalse()
+ }
+
+ @Test
+ fun isSafetyCenterEnabled_withFlagDisabled_returnsFalse() {
+ SafetyCenterFlags.setSafetyCenterEnabled(false)
+
+ val isSafetyCenterEnabled = safetyCenterManager.isSafetyCenterEnabledWithPermission()
+
+ assertThat(isSafetyCenterEnabled).isFalse()
+ }
+
+ private fun startSafetyCenterActivity() {
+ context.startActivity(
+ Intent(ACTION_SAFETY_CENTER)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ )
+ }
+}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
index 06f1e26e6..a13b4e425 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyEventTest.kt
@@ -18,13 +18,13 @@ package android.safetycenter.cts
import android.os.Build
import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreEqual
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreNotEqual
-import android.safetycenter.testers.ParcelableTester.assertThatRoundTripReturnsOriginal
+import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
+import android.safetycenter.testing.AnyTester.assertThatRepresentationsAreEqual
+import android.safetycenter.testing.AnyTester.assertThatRepresentationsAreNotEqual
+import android.safetycenter.testing.ParcelableTester.assertThatRoundTripReturnsOriginal
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
@@ -45,9 +45,9 @@ class SafetyEventTest {
@Test
fun getRefreshBroadcastId_returnsRefreshBroadcastId() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
+ .build()
assertThat(safetyEvent.refreshBroadcastId).isEqualTo(REFRESH_BROADCAST_ID)
}
@@ -55,9 +55,9 @@ class SafetyEventTest {
@Test
fun getSafetySourceIssueId_returnsSafetySourceIssueId() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .build()
assertThat(safetyEvent.safetySourceIssueId).isEqualTo(SAFETY_SOURCE_ISSUE_ID)
}
@@ -65,9 +65,9 @@ class SafetyEventTest {
@Test
fun getSafetySourceIssueActionId_returnsSafetySourceIssueActionId() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
assertThat(safetyEvent.safetySourceIssueActionId).isEqualTo(SAFETY_SOURCE_ISSUE_ACTION_ID)
}
@@ -75,10 +75,10 @@ class SafetyEventTest {
@Test
fun describeContents_returns0() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
assertThat(safetyEvent.describeContents()).isEqualTo(0)
}
@@ -86,10 +86,10 @@ class SafetyEventTest {
@Test
fun createFromParcel_withWriteToParcel_returnsOriginalSafetySourceData() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
assertThatRoundTripReturnsOriginal(safetyEvent, SafetyEvent.CREATOR)
}
@@ -98,9 +98,9 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withEqualByReference_areEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
+ .build()
val otherSafetyEvent = safetyEvent
assertThatRepresentationsAreEqual(safetyEvent, otherSafetyEvent)
@@ -109,15 +109,15 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withAllFieldsEqual_areEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
assertThatRepresentationsAreEqual(safetyEvent, otherSafetyEvent)
}
@@ -125,11 +125,11 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withDifferentSafetyEventTypes_areNotEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .build()
val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED)
+ .build()
assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
}
@@ -137,13 +137,13 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withDifferentRefreshBroadcastIds_areNotEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(REFRESH_BROADCAST_ID)
+ .build()
val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(OTHER_REFRESH_BROADCAST_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(OTHER_REFRESH_BROADCAST_ID)
+ .build()
assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
}
@@ -151,13 +151,13 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withDifferentIssueIds_areNotEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .build()
val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(OTHER_SAFETY_SOURCE_ISSUE_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(OTHER_SAFETY_SOURCE_ISSUE_ID)
+ .build()
assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
}
@@ -165,15 +165,15 @@ class SafetyEventTest {
@Test
fun hashCode_equals_toString_withDifferentActionIds_areNotEqual() {
val safetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
val otherSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
- .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
- .setSafetySourceIssueActionId(OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID)
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED)
+ .setSafetySourceIssueId(SAFETY_SOURCE_ISSUE_ID)
+ .setSafetySourceIssueActionId(OTHER_SAFETY_SOURCE_ISSUE_ACTION_ID)
+ .build()
assertThatRepresentationsAreNotEqual(safetyEvent, otherSafetyEvent)
}
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
index 2a8bff776..ed9136f04 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceErrorDetailsTest.kt
@@ -19,9 +19,9 @@ package android.safetycenter.cts
import android.os.Build
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetySourceErrorDetails
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreEqual
-import android.safetycenter.testers.AnyTester.assertThatRepresentationsAreNotEqual
-import android.safetycenter.testers.ParcelableTester.assertThatRoundTripReturnsOriginal
+import android.safetycenter.testing.AnyTester.assertThatRepresentationsAreEqual
+import android.safetycenter.testing.AnyTester.assertThatRepresentationsAreNotEqual
+import android.safetycenter.testing.ParcelableTester.assertThatRoundTripReturnsOriginal
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
@@ -64,15 +64,15 @@ class SafetySourceErrorDetailsTest {
@Test
fun equals_toString_withDifferentSafetyEvents_areNotEqual() {
val errorDetails = SafetySourceErrorDetails(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build())
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build())
val otherErrorDetails = SafetySourceErrorDetails(
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build())
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build())
assertThatRepresentationsAreNotEqual(errorDetails, otherErrorDetails)
}
companion object {
private val SAFETY_EVENT =
- SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
}
} \ No newline at end of file
diff --git a/tests/cts/safetycenter/src/android/safetycenter/testers/AnyTester.kt b/tests/cts/safetycenter/src/android/safetycenter/testing/AnyTester.kt
index f3fbf77a8..50c37a39a 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/testers/AnyTester.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/testing/AnyTester.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.safetycenter.testers
+package android.safetycenter.testing
import com.google.common.truth.Truth.assertThat
diff --git a/tests/cts/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt b/tests/cts/safetycenter/src/android/safetycenter/testing/ParcelableTester.kt
index f2c2482a1..0ba599993 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/testers/ParcelableTester.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/testing/ParcelableTester.kt
@@ -1,4 +1,4 @@
-package android.safetycenter.testers
+package android.safetycenter.testing
import android.os.Parcel
import android.os.Parcelable
diff --git a/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt
new file mode 100644
index 000000000..153390492
--- /dev/null
+++ b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterApisWithShellPermissions.kt
@@ -0,0 +1,156 @@
+/*
+ * 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.safetycenter.testing
+
+import android.Manifest.permission.MANAGE_SAFETY_CENTER
+import android.Manifest.permission.READ_SAFETY_CENTER_STATUS
+import android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE
+import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceData
+import android.safetycenter.SafetySourceErrorDetails
+import android.safetycenter.config.SafetyCenterConfig
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import java.util.concurrent.Executor
+
+/**
+ * Calls [SafetyCenterManager.isSafetyCenterEnabled] adopting Shell's [READ_SAFETY_CENTER_STATUS]
+ * permission.
+ */
+fun SafetyCenterManager.isSafetyCenterEnabledWithPermission() =
+ callWithShellPermissionIdentity({ isSafetyCenterEnabled }, READ_SAFETY_CENTER_STATUS)
+
+/**
+ * Calls [SafetyCenterManager.setSafetySourceData] adopting Shell's [SEND_SAFETY_CENTER_UPDATE]
+ * permission.
+ */
+fun SafetyCenterManager.setSafetySourceDataWithPermission(
+ safetySourceId: String,
+ safetySourceData: SafetySourceData?,
+ safetyEvent: SafetyEvent
+) =
+ callWithShellPermissionIdentity(
+ { setSafetySourceData(safetySourceId, safetySourceData, safetyEvent) },
+ SEND_SAFETY_CENTER_UPDATE
+ )
+
+/**
+ * Calls [SafetyCenterManager.getSafetySourceData] adopting Shell's [SEND_SAFETY_CENTER_UPDATE]
+ * permission.
+ */
+fun SafetyCenterManager.getSafetySourceDataWithPermission(id: String) =
+ callWithShellPermissionIdentity({ getSafetySourceData(id) }, SEND_SAFETY_CENTER_UPDATE)
+
+/**
+ * Calls [SafetyCenterManager.reportSafetySourceError] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.reportSafetySourceErrorWithPermission(
+ safetySourceId: String,
+ safetySourceErrorDetails: SafetySourceErrorDetails
+) =
+ callWithShellPermissionIdentity(
+ { reportSafetySourceError(safetySourceId, safetySourceErrorDetails) },
+ MANAGE_SAFETY_CENTER
+ )
+
+/**
+ * Calls [SafetyCenterManager.refreshSafetySources] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.refreshSafetySourcesWithPermission(refreshReason: Int) =
+ callWithShellPermissionIdentity({ refreshSafetySources(refreshReason) }, MANAGE_SAFETY_CENTER)
+
+/**
+ * Calls [SafetyCenterManager.getSafetyCenterData] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.getSafetyCenterDataWithPermission() =
+ callWithShellPermissionIdentity(::getSafetyCenterData, MANAGE_SAFETY_CENTER)
+
+/**
+ * Calls [SafetyCenterManager.addOnSafetyCenterDataChangedListener] adopting Shell's
+ * [MANAGE_SAFETY_CENTER] permission.
+ */
+fun SafetyCenterManager.addOnSafetyCenterDataChangedListenerWithPermission(
+ executor: Executor,
+ listener: OnSafetyCenterDataChangedListener
+) =
+ callWithShellPermissionIdentity(
+ { addOnSafetyCenterDataChangedListener(executor, listener) },
+ MANAGE_SAFETY_CENTER
+ )
+
+/**
+ * Calls [SafetyCenterManager.removeOnSafetyCenterDataChangedListener] adopting Shell's
+ * [MANAGE_SAFETY_CENTER] permission.
+ */
+fun SafetyCenterManager.removeOnSafetyCenterDataChangedListenerWithPermission(
+ listener: OnSafetyCenterDataChangedListener
+) =
+ callWithShellPermissionIdentity(
+ { removeOnSafetyCenterDataChangedListener(listener) },
+ MANAGE_SAFETY_CENTER
+ )
+
+/**
+ * Calls [SafetyCenterManager.dismissSafetyCenterIssue] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.dismissSafetyIssueWithPermission(safetyCenterIssueId: String) =
+ callWithShellPermissionIdentity({ dismissSafetyCenterIssue(safetyCenterIssueId) },
+ MANAGE_SAFETY_CENTER)
+
+/**
+ * Calls [SafetyCenterManager.executeSafetyCenterIssueAction] adopting Shell's
+ * [MANAGE_SAFETY_CENTER] permission.
+ */
+fun SafetyCenterManager.executeSafetyCenterActionWithPermission(
+ safetyCenterIssueId: String,
+ safetyCenterIssueActionId: String
+) =
+ callWithShellPermissionIdentity(
+ { executeSafetyCenterIssueAction(safetyCenterIssueId, safetyCenterIssueActionId) },
+ MANAGE_SAFETY_CENTER
+ )
+
+/**
+ * Calls [SafetyCenterManager.clearAllSafetySourceData] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.clearAllSafetySourceDataWithPermission() =
+ callWithShellPermissionIdentity({ clearAllSafetySourceData() }, MANAGE_SAFETY_CENTER)
+
+/**
+ * Calls [SafetyCenterManager.setSafetyCenterConfigOverride] adopting Shell's [MANAGE_SAFETY_CENTER]
+ * permission.
+ */
+fun SafetyCenterManager.setSafetyCenterConfigOverrideWithPermission(
+ safetyCenterConfig: SafetyCenterConfig
+) =
+ callWithShellPermissionIdentity(
+ { setSafetyCenterConfigOverride(safetyCenterConfig) },
+ MANAGE_SAFETY_CENTER
+ )
+
+/**
+ * Calls [SafetyCenterManager.clearSafetyCenterConfigOverride] adopting Shell's
+ * [MANAGE_SAFETY_CENTER] permission.
+ */
+fun SafetyCenterManager.clearSafetyCenterConfigOverrideWithPermission() =
+ callWithShellPermissionIdentity({ clearSafetyCenterConfigOverride() }, MANAGE_SAFETY_CENTER)
diff --git a/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterFlags.kt b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterFlags.kt
new file mode 100644
index 000000000..8ae335c7c
--- /dev/null
+++ b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetyCenterFlags.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.safetycenter.testing
+
+import android.Manifest.permission.WRITE_DEVICE_CONFIG
+import android.content.Context
+import android.content.res.Resources
+import android.provider.DeviceConfig
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+
+/** A class that facilitates working with Safety Center flags. */
+object SafetyCenterFlags {
+
+ /** Name of the flag that determines whether SafetyCenter is enabled. */
+ private const val PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"
+
+ /** Returns whether the device supports Safety Center. */
+ fun Context.deviceSupportsSafetyCenter() =
+ resources.getBoolean(
+ Resources.getSystem().getIdentifier("config_enableSafetyCenter", "bool", "android")
+ )
+
+ /** Sets the Safety Center device config flag to the given boolean [value]. */
+ fun setSafetyCenterEnabled(value: Boolean) {
+ callWithShellPermissionIdentity(
+ {
+ val valueWasSet =
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ PROPERTY_SAFETY_CENTER_ENABLED,
+ /* value = */ value.toString(),
+ /* makeDefault = */ false
+ )
+ if (!valueWasSet) {
+ throw IllegalStateException("Could not set Safety Center flag value to: $value")
+ }
+ },
+ WRITE_DEVICE_CONFIG
+ )
+ }
+} \ No newline at end of file
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetySourceBroadcastReceiver.kt
index 5f8e8b890..8097d9dbb 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetySourceBroadcastReceiver.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/testing/SafetySourceBroadcastReceiver.kt
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-package android.safetycenter.cts
+package android.safetycenter.testing
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.safetycenter.SafetyCenterManager
import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA
+import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA
import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetySourceData
import android.safetycenter.SafetyEvent
import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
+import android.safetycenter.SafetySourceData
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
@@ -48,46 +48,49 @@ class SafetySourceBroadcastReceiver : BroadcastReceiver() {
when (intent.getIntExtra(EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE, -1)) {
EXTRA_REFRESH_REQUEST_TYPE_GET_DATA ->
safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!,
- safetySourceDataOnPageOpen!!,
- EVENT_REFRESH_REQUESTED
+ safetySourceId!!,
+ safetySourceDataOnPageOpen!!,
+ EVENT_REFRESH_REQUESTED
)
EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA ->
safetyCenterManager.setSafetySourceDataWithPermission(
- safetySourceId!!,
- safetySourceDataOnRescanClick!!,
- EVENT_REFRESH_REQUESTED
+ safetySourceId!!,
+ safetySourceDataOnRescanClick!!,
+ EVENT_REFRESH_REQUESTED
)
}
- runBlocking {
- updateChannel.send(Unit)
- }
+ runBlocking { updateChannel.send(Unit) }
}
companion object {
- private var updateChannel = Channel<Unit>()
private val EVENT_REFRESH_REQUESTED =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId("refresh_id")
- .build()
+ SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId("refresh_id")
+ .build()
+
+ @Volatile
+ private var updateChannel = Channel<Unit>()
+
+ @Volatile
var safetySourceId: String? = null
+
+ @Volatile
var safetySourceDataOnPageOpen: SafetySourceData? = null
+
+ @Volatile
var safetySourceDataOnRescanClick: SafetySourceData? = null
fun reset() {
safetySourceId = null
safetySourceDataOnRescanClick = null
safetySourceDataOnPageOpen = null
+ updateChannel.cancel()
updateChannel = Channel()
}
fun waitTillOnReceiveComplete(duration: Duration) {
- runBlocking {
- withTimeout(duration.toMillis()) {
- updateChannel.receive()
- }
- }
+ runBlocking { withTimeout(duration.toMillis()) { updateChannel.receive() } }
}
}
}