summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SafetyCenter/Config/Android.bp1
-rw-r--r--SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java25
-rw-r--r--SafetyCenter/Config/tests/Android.bp1
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt57
-rw-r--r--SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt16
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_disabled_no_private.xml18
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_hidden_with_search_no_private.xml17
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_no_private.xml17
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_hidden_with_private.xml15
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_with_private.xml17
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_issue_only_safety_source_with_private.xml12
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_static_safety_source_with_primary_and_private.xml16
-rw-r--r--SafetyCenter/Config/tests/res/raw-v35/config_valid.xml197
-rw-r--r--SafetyCenter/Config/tests/res/raw/config_static_safety_source_with_private_profile.xml17
-rw-r--r--SafetyCenter/ConfigLintChecker/Android.bp119
-rw-r--r--SafetyCenter/Resources/Android.bp7
-rw-r--r--SafetyCenter/Resources/res/raw-v35/safety_center_config.xml1
-rw-r--r--SafetyCenter/Resources/res/values-v35/strings.xml3
-rw-r--r--flags/flags.aconfig8
-rw-r--r--framework-s/api/system-current.txt2
-rw-r--r--framework-s/java/android/safetycenter/config/SafetySource.java100
-rw-r--r--framework-s/java/android/safetycenter/config/safety_center_config-v35.xsd223
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataFactory.java9
-rw-r--r--tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt101
-rw-r--r--tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt61
-rw-r--r--tests/utils/safetycenter/Android.bp1
-rw-r--r--tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt16
27 files changed, 983 insertions, 94 deletions
diff --git a/SafetyCenter/Config/Android.bp b/SafetyCenter/Config/Android.bp
index d6423288a..48c8eab46 100644
--- a/SafetyCenter/Config/Android.bp
+++ b/SafetyCenter/Config/Android.bp
@@ -40,6 +40,7 @@ java_library {
],
static_libs: [
"modules-utils-build",
+ "permissions-aconfig-flags-lib",
],
apex_available: [
"com.android.permission",
diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
index b6730f36f..38eee9e51 100644
--- a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
+++ b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java
@@ -33,10 +33,12 @@ import android.content.res.Resources;
import android.safetycenter.config.SafetyCenterConfig;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
+import android.util.Log;
import androidx.annotation.RequiresApi;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.flags.Flags;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -49,6 +51,7 @@ import java.io.InputStream;
@RequiresApi(TIRAMISU)
public final class SafetyCenterConfigParser {
+ private static final String TAG = "SafetyCenterConfigParser";
private static final String TAG_SAFETY_CENTER_CONFIG = "safety-center-config";
private static final String TAG_SAFETY_SOURCES_CONFIG = "safety-sources-config";
private static final String TAG_SAFETY_SOURCES_GROUP = "safety-sources-group";
@@ -64,6 +67,8 @@ public final class SafetyCenterConfigParser {
private static final String ATTR_SAFETY_SOURCE_PACKAGE_NAME = "packageName";
private static final String ATTR_SAFETY_SOURCE_TITLE = "title";
private static final String ATTR_SAFETY_SOURCE_TITLE_FOR_WORK = "titleForWork";
+ private static final String ATTR_SAFETY_SOURCE_TITLE_FOR_PRIVATE_PROFILE =
+ "titleForPrivateProfile";
private static final String ATTR_SAFETY_SOURCE_SUMMARY = "summary";
private static final String ATTR_SAFETY_SOURCE_INTENT_ACTION = "intentAction";
private static final String ATTR_SAFETY_SOURCE_PROFILE = "profile";
@@ -270,6 +275,26 @@ public final class SafetyCenterConfigParser {
parser.getAttributeName(i),
resources));
break;
+ case ATTR_SAFETY_SOURCE_TITLE_FOR_PRIVATE_PROFILE:
+ if (SdkLevel.isAtLeastV()) {
+ if (Flags.privateProfileTitleApi()) {
+ builder.setTitleForPrivateProfileResId(
+ parseStringResourceName(
+ parser.getAttributeValue(i),
+ name,
+ parser.getAttributeName(i),
+ resources));
+ } else {
+ Log.i(
+ TAG,
+ String.format(
+ "Ignoring attribute %s.%s",
+ name, ATTR_SAFETY_SOURCE_TITLE_FOR_PRIVATE_PROFILE));
+ }
+ break;
+ } else {
+ throw attributeUnexpected(name, parser.getAttributeName(i));
+ }
case ATTR_SAFETY_SOURCE_SUMMARY:
builder.setSummaryResId(
parseStringResourceName(
diff --git a/SafetyCenter/Config/tests/Android.bp b/SafetyCenter/Config/tests/Android.bp
index 3adedfc25..20a536237 100644
--- a/SafetyCenter/Config/tests/Android.bp
+++ b/SafetyCenter/Config/tests/Android.bp
@@ -33,6 +33,7 @@ android_test {
"compatibility-device-util-axt",
"safety-center-config",
"safety-center-test-util-lib",
+ "permissions-aconfig-flags-lib",
],
test_suites: [
"general-tests",
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
index 64775d7fe..98b899ebf 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt
@@ -19,6 +19,7 @@ package com.android.safetycenter.config
import android.content.Context
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
import com.android.safetycenter.config.tests.R
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
@@ -63,18 +64,39 @@ class ParserConfigInvalidTest {
fun parameters() =
arrayOf(
Params(
+ "ConfigDynamicSafetySourceAllDisabledNoPrivate",
+ R.raw.config_dynamic_safety_source_all_disabled_no_private,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForPrivateProfile missing",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigDynamicSafetySourceAllDisabledNoWork",
R.raw.config_dynamic_safety_source_all_disabled_no_work,
"Element dynamic-safety-source invalid",
"Required attribute titleForWork missing"
),
Params(
+ "ConfigDynamicSafetySourceAllHiddenWithSearchNoPrivate",
+ R.raw.config_dynamic_safety_source_all_hidden_with_search_no_private,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForPrivateProfile missing",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigDynamicSafetySourceAllHiddenWithSearchNoWork",
R.raw.config_dynamic_safety_source_all_hidden_with_search_no_work,
"Element dynamic-safety-source invalid",
"Required attribute titleForWork missing"
),
Params(
+ "ConfigDynamicSafetySourceAllNoPrivate",
+ R.raw.config_dynamic_safety_source_all_no_private,
+ "Element dynamic-safety-source invalid",
+ "Required attribute titleForPrivateProfile missing",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigDynamicSafetySourceAllNoWork",
R.raw.config_dynamic_safety_source_all_no_work,
"Element dynamic-safety-source invalid",
@@ -160,12 +182,26 @@ class ParserConfigInvalidTest {
"Required attribute title missing"
),
Params(
+ "ConfigDynamicSafetySourcePrimaryHiddenWithPrivate",
+ R.raw.config_dynamic_safety_source_primary_hidden_with_private,
+ "Element dynamic-safety-source invalid",
+ "Prohibited attribute titleForPrivateProfile present",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigDynamicSafetySourcePrimaryHiddenWithWork",
R.raw.config_dynamic_safety_source_primary_hidden_with_work,
"Element dynamic-safety-source invalid",
"Prohibited attribute titleForWork present"
),
Params(
+ "ConfigDynamicSafetySourcePrimaryWithPrivate",
+ R.raw.config_dynamic_safety_source_primary_with_private,
+ "Element dynamic-safety-source invalid",
+ "Prohibited attribute titleForPrivateProfile present",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigDynamicSafetySourcePrimaryWithWork",
R.raw.config_dynamic_safety_source_primary_with_work,
"Element dynamic-safety-source invalid",
@@ -226,6 +262,13 @@ class ParserConfigInvalidTest {
"Prohibited attribute intentAction present"
),
Params(
+ "ConfigIssueOnlySafetySourceWithPrivate",
+ R.raw.config_issue_only_safety_source_with_private,
+ "Element issue-only-safety-source invalid",
+ "Prohibited attribute titleForPrivateProfile present",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigIssueOnlySafetySourceWithSearch",
R.raw.config_issue_only_safety_source_with_search,
"Element issue-only-safety-source invalid",
@@ -425,12 +468,26 @@ class ParserConfigInvalidTest {
SdkLevel.isAtLeastU()
),
Params(
+ "ConfigStaticSafetySourceWithPrimaryAndPrivate",
+ R.raw.config_static_safety_source_with_primary_and_private,
+ "Element static-safety-source invalid",
+ "Prohibited attribute titleForPrivateProfile present",
+ SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()
+ ),
+ Params(
"ConfigStaticSafetySourceWithPrimaryAndWork",
R.raw.config_static_safety_source_with_primary_and_work,
"Element static-safety-source invalid",
"Prohibited attribute titleForWork present"
),
Params(
+ "ConfigStaticSafetySourceWithPrivatePreV",
+ R.raw.config_static_safety_source_with_private_profile,
+ "Element static-safety-source invalid",
+ "Unexpected attribute static-safety-source.titleForPrivateProfile",
+ !SdkLevel.isAtLeastV()
+ ),
+ Params(
"ConfigStaticSafetySourceWithRefresh",
R.raw.config_static_safety_source_with_refresh,
"Element static-safety-source invalid",
diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
index b63ccead7..5e8d04597 100644
--- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
+++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt
@@ -77,6 +77,9 @@ class ParserConfigValidTest {
addPackageCertificateHash("feed1")
addPackageCertificateHash("feed2")
}
+ if (SdkLevel.isAtLeastV()) {
+ setTitleForPrivateProfileResId(R.string.reference)
+ }
}
.build()
)
@@ -101,6 +104,9 @@ class ParserConfigValidTest {
addPackageCertificateHash("feed1")
addPackageCertificateHash("feed2")
}
+ if (SdkLevel.isAtLeastV()) {
+ setTitleForPrivateProfileResId(R.string.reference)
+ }
}
.build()
)
@@ -133,6 +139,11 @@ class ParserConfigValidTest {
.setProfile(SafetySource.PROFILE_ALL)
.setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
.setSearchTermsResId(R.string.reference)
+ .apply {
+ if (SdkLevel.isAtLeastV()) {
+ setTitleForPrivateProfileResId(R.string.reference)
+ }
+ }
.build()
)
.build()
@@ -159,6 +170,11 @@ class ParserConfigValidTest {
.setIntentAction("intent")
.setProfile(SafetySource.PROFILE_ALL)
.setSearchTermsResId(R.string.reference)
+ .apply {
+ if (SdkLevel.isAtLeastV()) {
+ setTitleForPrivateProfileResId(R.string.reference)
+ }
+ }
.build()
)
.build()
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_disabled_no_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_disabled_no_private.xml
new file mode 100644
index 000000000..dae6ca754
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_disabled_no_private.xml
@@ -0,0 +1,18 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ initialDisplayState="disabled"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_hidden_with_search_no_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_hidden_with_search_no_private.xml
new file mode 100644
index 000000000..e1852b6ec
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_hidden_with_search_no_private.xml
@@ -0,0 +1,17 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ profile="all_profiles"
+ initialDisplayState="hidden"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_no_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_no_private.xml
new file mode 100644
index 000000000..8446b71cc
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_all_no_private.xml
@@ -0,0 +1,17 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_hidden_with_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_hidden_with_private.xml
new file mode 100644
index 000000000..3d5840b03
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_hidden_with_private.xml
@@ -0,0 +1,15 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ profile="primary_profile_only"
+ initialDisplayState="hidden"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_with_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_with_private.xml
new file mode 100644
index 000000000..b95a3ed6e
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_dynamic_safety_source_primary_with_private.xml
@@ -0,0 +1,17 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="id"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_issue_only_safety_source_with_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_issue_only_safety_source_with_private.xml
new file mode 100644
index 000000000..7b2484a41
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_issue_only_safety_source_with_private.xml
@@ -0,0 +1,12 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id">
+ <issue-only-safety-source
+ id="id"
+ packageName="package"
+ profile="all_profiles"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_static_safety_source_with_primary_and_private.xml b/SafetyCenter/Config/tests/res/raw-v35/config_static_safety_source_with_primary_and_private.xml
new file mode 100644
index 000000000..0ab3d885b
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_static_safety_source_with_primary_and_private.xml
@@ -0,0 +1,16 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw-v35/config_valid.xml b/SafetyCenter/Config/tests/res/raw-v35/config_valid.xml
new file mode 100644
index 000000000..e49a6cdc4
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw-v35/config_valid.xml
@@ -0,0 +1,197 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="dynamic"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <dynamic-safety-source
+ id="dynamic_barebone"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <dynamic-safety-source
+ id="dynamic_all_optional"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ initialDisplayState="disabled"
+ maxSeverityLevel="300"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"
+ loggingAllowed="false"
+ refreshOnPageOpenAllowed="true"
+ notificationsAllowed="true"
+ deduplicationGroup="group"
+ packageCertificateHashes="feed1,feed2"/>
+ <dynamic-safety-source
+ id="@com.android.safetycenter.config.tests:string/dynamic_all_references_id"
+ packageName="@com.android.safetycenter.config.tests:string/dynamic_all_references_package_name"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="@com.android.safetycenter.config.tests:string/dynamic_all_references_intent_action"
+ profile="@com.android.safetycenter.config.tests:string/dynamic_all_references_profile"
+ initialDisplayState="@com.android.safetycenter.config.tests:string/dynamic_all_references_initial_display_state"
+ maxSeverityLevel="@com.android.safetycenter.config.tests:string/dynamic_all_references_max_severity_level"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"
+ loggingAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_logging_allowed"
+ refreshOnPageOpenAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_refresh_on_page_open_allowed"
+ notificationsAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_notifications_allowed"
+ deduplicationGroup="@com.android.safetycenter.config.tests:string/dynamic_all_references_deduplication_group"
+ packageCertificateHashes="@com.android.safetycenter.config.tests:string/dynamic_all_references_package_cert_hashes"/>
+ <dynamic-safety-source
+ id="dynamic_disabled"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ profile="primary_profile_only"
+ initialDisplayState="disabled"/>
+ <dynamic-safety-source
+ id="dynamic_hidden"
+ packageName="package"
+ profile="all_profiles"
+ initialDisplayState="hidden"/>
+ <dynamic-safety-source
+ id="dynamic_hidden_with_search"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ initialDisplayState="hidden"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="static"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="static_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <static-safety-source
+ id="static_all_optional"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"
+ searchTerms="@com.android.safetycenter.config.tests:string/reference"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="issue_only">
+ <issue-only-safety-source
+ id="issue_only_barebone"
+ packageName="package"
+ profile="primary_profile_only"/>
+ <issue-only-safety-source
+ id="issue_only_all_optional"
+ packageName="package"
+ profile="all_profiles"
+ maxSeverityLevel="300"
+ loggingAllowed="false"
+ refreshOnPageOpenAllowed="true"
+ notificationsAllowed="true"
+ deduplicationGroup="group"
+ packageCertificateHashes="feed1,feed2"/>
+ <issue-only-safety-source
+ id="id_test_abcxyz_ABCXYZ_012789"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ id="mixed"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <dynamic-safety-source
+ id="mixed_dynamic_barebone"
+ packageName="package"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ <issue-only-safety-source
+ id="mixed_issue_only_barebone"
+ packageName="package"
+ profile="primary_profile_only"/>
+ <static-safety-source
+ id="mixed_static_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateful"
+ id="stateful_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="stateful_barebone_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateful"
+ id="stateful_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <static-safety-source
+ id="stateful_all_optional_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateless"
+ id="stateless_barebone"
+ title="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="stateless_barebone_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="stateless"
+ id="stateless_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <static-safety-source
+ id="stateless_all_optional_source"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="hidden"
+ id="hidden_barebone">
+ <issue-only-safety-source
+ id="hidden_barebone_source"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ <safety-sources-group
+ type="hidden"
+ id="hidden_all_optional"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ statelessIconType="privacy">
+ <issue-only-safety-source
+ id="hidden_all_optional_source"
+ packageName="package"
+ profile="primary_profile_only"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/Config/tests/res/raw/config_static_safety_source_with_private_profile.xml b/SafetyCenter/Config/tests/res/raw/config_static_safety_source_with_private_profile.xml
new file mode 100644
index 000000000..f790baec9
--- /dev/null
+++ b/SafetyCenter/Config/tests/res/raw/config_static_safety_source_with_private_profile.xml
@@ -0,0 +1,17 @@
+<safety-center-config>
+ <safety-sources-config>
+ <safety-sources-group
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference">
+ <static-safety-source
+ id="id"
+ title="@com.android.safetycenter.config.tests:string/reference"
+ titleForWork="@com.android.safetycenter.config.tests:string/reference"
+ titleForPrivateProfile="@com.android.safetycenter.config.tests:string/reference"
+ summary="@com.android.safetycenter.config.tests:string/reference"
+ intentAction="intent"
+ profile="all_profiles"/>
+ </safety-sources-group>
+ </safety-sources-config>
+</safety-center-config>
diff --git a/SafetyCenter/ConfigLintChecker/Android.bp b/SafetyCenter/ConfigLintChecker/Android.bp
index fad0165df..7c615d2f4 100644
--- a/SafetyCenter/ConfigLintChecker/Android.bp
+++ b/SafetyCenter/ConfigLintChecker/Android.bp
@@ -12,64 +12,65 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package {
- default_team: "trendy_team_android_permissions",
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
+// TODO(b/322944911): Reconsider enabling linter checker
+//package {
+// default_team: "trendy_team_android_permissions",
+// default_applicable_licenses: ["Android-Apache-2.0"],
+//}
-java_library_host {
- name: "ConfigLintChecker",
- srcs: [
- "java/**/*.java",
- "java/**/*.kt",
- ":safetycenter-annotations-sources",
- ":safetycenter-config-api-sources",
- ":safetycenter-config-parser-sources",
- ],
- plugins: ["auto_service_plugin"],
- libs: [
- "androidx.annotation_annotation", // For androidx.annotation.RequiresApi
- "auto_service_annotations",
- "core-xml-for-host", // For org.xmlpull.v1.*
- "framework-annotations-lib", // For com.android.annotation.*
- "layoutlib_api-prebuilt", // For com.android.resources.ResourceFolderType
- "lint_api",
- ],
- java_resources: [":safetycenter-config-schemas"],
- jarjar_rules: "jarjar-rules.txt",
- kotlincflags: ["-Xjvm-default=all"],
- visibility: [
- "//packages/modules/Permission:__subpackages__",
- "//vendor:__subpackages__",
- ],
-}
+//java_library_host {
+// name: "ConfigLintChecker",
+// srcs: [
+// "java/**/*.java",
+// "java/**/*.kt",
+// ":safetycenter-annotations-sources",
+// ":safetycenter-config-api-sources",
+// ":safetycenter-config-parser-sources",
+// ],
+// plugins: ["auto_service_plugin"],
+// libs: [
+// "androidx.annotation_annotation", // For androidx.annotation.RequiresApi
+// "auto_service_annotations",
+// "core-xml-for-host", // For org.xmlpull.v1.*
+// "framework-annotations-lib", // For com.android.annotation.*
+// "layoutlib_api-prebuilt", // For com.android.resources.ResourceFolderType
+// "lint_api",
+// ],
+// java_resources: [":safetycenter-config-schemas"],
+// jarjar_rules: "jarjar-rules.txt",
+// kotlincflags: ["-Xjvm-default=all"],
+// visibility: [
+// "//packages/modules/Permission:__subpackages__",
+// "//vendor:__subpackages__",
+// ],
+//}
-java_test_host {
- name: "ConfigLintCheckerTest",
- srcs: [
- "tests/java/**/*.kt",
- ],
- static_libs: [
- "ConfigLintChecker",
- "junit",
- "lint",
- "lint_tests",
- ],
- test_options: {
- unit_test: true,
- tradefed_options: [
- {
- // lint bundles in some classes that were built with older versions
- // of libraries, and no longer load. Since tradefed tries to load
- // all classes in the jar to look for tests, it crashes loading them.
- // Exclude these classes from tradefed's search.
- name: "exclude-paths",
- value: "org/apache",
- },
- {
- name: "exclude-paths",
- value: "META-INF",
- },
- ],
- },
-}
+//java_test_host {
+// name: "ConfigLintCheckerTest",
+// srcs: [
+// "tests/java/**/*.kt",
+// ],
+// static_libs: [
+// "ConfigLintChecker",
+// "junit",
+// "lint",
+// "lint_tests",
+// ],
+// test_options: {
+// unit_test: true,
+// tradefed_options: [
+// {
+// // lint bundles in some classes that were built with older versions
+// // of libraries, and no longer load. Since tradefed tries to load
+// // all classes in the jar to look for tests, it crashes loading them.
+// // Exclude these classes from tradefed's search.
+// name: "exclude-paths",
+// value: "org/apache",
+// },
+// {
+// name: "exclude-paths",
+// value: "META-INF",
+// },
+// ],
+// },
+//}
diff --git a/SafetyCenter/Resources/Android.bp b/SafetyCenter/Resources/Android.bp
index 6f635c885..a10ea7f1a 100644
--- a/SafetyCenter/Resources/Android.bp
+++ b/SafetyCenter/Resources/Android.bp
@@ -42,9 +42,10 @@ android_app {
min_sdk_version: "30",
apex_available: ["com.android.permission"],
certificate: ":com.android.safetycenter.resources.certificate",
- lint: {
- extra_check_modules: ["ConfigLintChecker"],
- },
+ // TODO(b/322944911): Reconsider enabling linter checker
+ //lint: {
+ // extra_check_modules: ["ConfigLintChecker"],
+ //},
static_libs: [
"SafetyCenterResourcesShared",
],
diff --git a/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml b/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml
index 5d626757c..cb49e9d36 100644
--- a/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml
+++ b/SafetyCenter/Resources/res/raw-v35/safety_center_config.xml
@@ -35,6 +35,7 @@
profile="all_profiles"
title="@com.android.safetycenter.resources:string/biometrics_title"
titleForWork="@com.android.safetycenter.resources:string/biometrics_title_for_work"
+ titleForPrivateProfile="@com.android.safetycenter.resources:string/biometrics_title_for_private_profile"
searchTerms="@com.android.safetycenter.resources:string/biometrics_search_terms"
initialDisplayState="hidden"/>
</safety-sources-group>
diff --git a/SafetyCenter/Resources/res/values-v35/strings.xml b/SafetyCenter/Resources/res/values-v35/strings.xml
index af43f11f2..bdbc4b648 100644
--- a/SafetyCenter/Resources/res/values-v35/strings.xml
+++ b/SafetyCenter/Resources/res/values-v35/strings.xml
@@ -20,6 +20,9 @@
<string name="cellular_network_security_title" description="The title of the group of safety settings relating to cellular network security">Cellular network security</string>
<string name="cellular_network_security_summary" description="The summary of the group of safety settings relating to cellular network security, which describes the group contents">Network type, encryption, notification controls</string>
+ <!-- Device unlock -->
+ <string name="biometrics_title_for_private_profile" description="The default title of the setting for managing biometric options on the device for private space"><!-- Empty placeholder--></string>
+
<!-- More settings -->
<string name="private_space_title" description="The title of the entry for Private Space">Private Space</string>
<string name="private_space_summary" description="The summary of the entry for Private Space settings, which describes the page contents">Setup Private Space, and more</string>
diff --git a/flags/flags.aconfig b/flags/flags.aconfig
index 441e3584e..8bf3a63ab 100644
--- a/flags/flags.aconfig
+++ b/flags/flags.aconfig
@@ -15,6 +15,14 @@ flag {
is_fixed_read_only: true
}
+flag {
+ name: "private_profile_title_api"
+ namespace: "permissions"
+ description: "This flag is used to guard the private profile title api in safety center"
+ bug: "286539356"
+ is_fixed_read_only: true
+}
+
# TODO: Remove when wear_privacy_dashboard_enabled_read_only reaches to the next stage.
flag {
name: "wear_privacy_dashboard_enabled"
diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt
index b4dfafba2..3712eae97 100644
--- a/framework-s/api/system-current.txt
+++ b/framework-s/api/system-current.txt
@@ -570,6 +570,7 @@ package android.safetycenter.config {
method public int getProfile();
method @StringRes public int getSearchTermsResId();
method @StringRes public int getSummaryResId();
+ method @FlaggedApi("com.android.permission.flags.private_profile_title_api") @StringRes public int getTitleForPrivateProfileResId();
method @StringRes public int getTitleForWorkResId();
method @StringRes public int getTitleResId();
method public int getType();
@@ -605,6 +606,7 @@ package android.safetycenter.config {
method @NonNull public android.safetycenter.config.SafetySource.Builder setRefreshOnPageOpenAllowed(boolean);
method @NonNull public android.safetycenter.config.SafetySource.Builder setSearchTermsResId(@StringRes int);
method @NonNull public android.safetycenter.config.SafetySource.Builder setSummaryResId(@StringRes int);
+ method @FlaggedApi("com.android.permission.flags.private_profile_title_api") @NonNull public android.safetycenter.config.SafetySource.Builder setTitleForPrivateProfileResId(@StringRes int);
method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleForWorkResId(@StringRes int);
method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleResId(@StringRes int);
}
diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java
index 8aa897850..5502ca950 100644
--- a/framework-s/java/android/safetycenter/config/SafetySource.java
+++ b/framework-s/java/android/safetycenter/config/SafetySource.java
@@ -18,9 +18,11 @@ package android.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM;
import static java.util.Objects.requireNonNull;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,6 +36,7 @@ import android.util.ArraySet;
import androidx.annotation.RequiresApi;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -182,6 +185,9 @@ public final class SafetySource implements Parcelable {
builder.addPackageCertificateHash(certs.get(i));
}
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ builder.setTitleForPrivateProfileResId(in.readInt());
+ }
return builder.build();
}
@@ -207,6 +213,7 @@ public final class SafetySource implements Parcelable {
private final boolean mNotificationsAllowed;
@Nullable final String mDeduplicationGroup;
@NonNull private final Set<String> mPackageCertificateHashes;
+ @StringRes private final int mTitleForPrivateProfileResId;
private SafetySource(
@SafetySourceType int type,
@@ -224,7 +231,8 @@ public final class SafetySource implements Parcelable {
boolean refreshOnPageOpenAllowed,
boolean notificationsAllowed,
@Nullable String deduplicationGroup,
- @NonNull Set<String> packageCertificateHashes) {
+ @NonNull Set<String> packageCertificateHashes,
+ @StringRes int titleForPrivateProfileResId) {
mType = type;
mId = id;
mPackageName = packageName;
@@ -241,6 +249,7 @@ public final class SafetySource implements Parcelable {
mNotificationsAllowed = notificationsAllowed;
mDeduplicationGroup = deduplicationGroup;
mPackageCertificateHashes = Set.copyOf(packageCertificateHashes);
+ mTitleForPrivateProfileResId = titleForPrivateProfileResId;
}
/** Returns the type of this safety source. */
@@ -347,6 +356,37 @@ public final class SafetySource implements Parcelable {
}
/**
+ * Returns the resource id of the title for private profile of this safety source.
+ *
+ * <p>The id refers to a string resource that is either accessible from any resource context or
+ * that is accessible from the same resource context that was used to load the Safety Center
+ * configuration. The id is {@link Resources#ID_NULL} when a title for private profile is not
+ * provided.
+ *
+ * @throws UnsupportedOperationException if the source is of type {@link
+ * SafetySource#SAFETY_SOURCE_TYPE_ISSUE_ONLY} or if the profile property of the source is
+ * set to {@link SafetySource#PROFILE_PRIMARY}
+ */
+ @FlaggedApi(Flags.FLAG_PRIVATE_PROFILE_TITLE_API)
+ @RequiresApi(VANILLA_ICE_CREAM)
+ @StringRes
+ public int getTitleForPrivateProfileResId() {
+ if (!SdkLevel.isAtLeastV()) {
+ throw new UnsupportedOperationException(
+ "getTitleForPrivateProfileResId unsupported for SDKs lower than V");
+ }
+ if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
+ throw new UnsupportedOperationException(
+ "getTitleForPrivateProfileResId unsupported for issue-only safety source");
+ }
+ if (mProfile == PROFILE_PRIMARY) {
+ throw new UnsupportedOperationException(
+ "getTitleForPrivateProfileResId unsupported for primary profile safety source");
+ }
+ return mTitleForPrivateProfileResId;
+ }
+
+ /**
* Returns the resource id of the summary of this safety source.
*
* <p>The id refers to a string resource that is either accessible from any resource context or
@@ -554,7 +594,8 @@ public final class SafetySource implements Parcelable {
&& mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed
&& mNotificationsAllowed == that.mNotificationsAllowed
&& Objects.equals(mDeduplicationGroup, that.mDeduplicationGroup)
- && Objects.equals(mPackageCertificateHashes, that.mPackageCertificateHashes);
+ && Objects.equals(mPackageCertificateHashes, that.mPackageCertificateHashes)
+ && mTitleForPrivateProfileResId == that.mTitleForPrivateProfileResId;
}
@Override
@@ -575,7 +616,8 @@ public final class SafetySource implements Parcelable {
mRefreshOnPageOpenAllowed,
mNotificationsAllowed,
mDeduplicationGroup,
- mPackageCertificateHashes);
+ mPackageCertificateHashes,
+ mTitleForPrivateProfileResId);
}
@Override
@@ -613,6 +655,8 @@ public final class SafetySource implements Parcelable {
+ mDeduplicationGroup
+ ", mPackageCertificateHashes="
+ mPackageCertificateHashes
+ + ", mTitleForPrivateProfileResId="
+ + mTitleForPrivateProfileResId
+ '}';
}
@@ -641,6 +685,9 @@ public final class SafetySource implements Parcelable {
dest.writeString(mDeduplicationGroup);
dest.writeStringList(List.copyOf(mPackageCertificateHashes));
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ dest.writeInt(mTitleForPrivateProfileResId);
+ }
}
/** Builder class for {@link SafetySource}. */
@@ -662,6 +709,7 @@ public final class SafetySource implements Parcelable {
@Nullable private Boolean mNotificationsAllowed;
@Nullable private String mDeduplicationGroup;
@NonNull private final ArraySet<String> mPackageCertificateHashes = new ArraySet<>();
+ @Nullable @StringRes private Integer mTitleForPrivateProfileResId;
/** Creates a {@link Builder} for a {@link SafetySource}. */
public Builder(@SafetySourceType int type) {
@@ -692,6 +740,7 @@ public final class SafetySource implements Parcelable {
mNotificationsAllowed = safetySource.mNotificationsAllowed;
mDeduplicationGroup = safetySource.mDeduplicationGroup;
mPackageCertificateHashes.addAll(safetySource.mPackageCertificateHashes);
+ mTitleForPrivateProfileResId = safetySource.mTitleForPrivateProfileResId;
}
/**
@@ -759,6 +808,32 @@ public final class SafetySource implements Parcelable {
}
/**
+ * Sets the resource id of the title for work of this safety source.
+ *
+ * <p>The id must refer to a string resource that is either accessible from any resource
+ * context or that is accessible from the same resource context that was used to load the
+ * Safety Center configuration. The id defaults to {@link Resources#ID_NULL} when a title
+ * for work is not provided.
+ *
+ * <p>The title for work is required if the profile property of the source is set to {@link
+ * SafetySource#PROFILE_ALL} and either the source is of type static or the source is a
+ * source of type dynamic that is not hidden and that does not provide search terms. The
+ * title for work is prohibited for sources of type issue-only and if the profile property
+ * of the source is not set to {@link SafetySource#PROFILE_ALL}.
+ */
+ @FlaggedApi(Flags.FLAG_PRIVATE_PROFILE_TITLE_API)
+ @RequiresApi(VANILLA_ICE_CREAM)
+ @NonNull
+ public Builder setTitleForPrivateProfileResId(@StringRes int titleForPrivateProfileResId) {
+ if (!SdkLevel.isAtLeastV()) {
+ throw new UnsupportedOperationException(
+ "setTitleForPrivateProfileResId unsupported for SDKs lower than V");
+ }
+ mTitleForPrivateProfileResId = titleForPrivateProfileResId;
+ return this;
+ }
+
+ /**
* Sets the resource id of the summary of this safety source.
*
* <p>The id must refer to a string resource that is either accessible from any resource
@@ -984,7 +1059,7 @@ public final class SafetySource implements Parcelable {
PROFILE_NONE,
PROFILE_PRIMARY,
PROFILE_ALL);
- boolean hasWork = profile == PROFILE_ALL;
+ boolean hasAllProfiles = profile == PROFILE_ALL;
int searchTermsResId =
BuilderUtils.validateResId(
@@ -1000,8 +1075,8 @@ public final class SafetySource implements Parcelable {
BuilderUtils.validateResId(
mTitleForWorkResId,
"titleForWork",
- hasWork && titleRequired,
- !hasWork || isIssueOnly);
+ hasAllProfiles && titleRequired,
+ !hasAllProfiles || isIssueOnly);
int summaryResId =
BuilderUtils.validateResId(
@@ -1052,6 +1127,16 @@ public final class SafetySource implements Parcelable {
packageCertificateHashes, "packageCertificateHashes", false, isStatic);
}
+ int titleForPrivateProfileResId = Resources.ID_NULL;
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ titleForPrivateProfileResId =
+ BuilderUtils.validateResId(
+ mTitleForPrivateProfileResId,
+ "titleForPrivateProfile",
+ hasAllProfiles && titleRequired,
+ !hasAllProfiles || isIssueOnly);
+ }
+
return new SafetySource(
type,
id,
@@ -1068,7 +1153,8 @@ public final class SafetySource implements Parcelable {
refreshOnPageOpenAllowed,
notificationsAllowed,
deduplicationGroup,
- packageCertificateHashes);
+ packageCertificateHashes,
+ titleForPrivateProfileResId);
}
}
}
diff --git a/framework-s/java/android/safetycenter/config/safety_center_config-v35.xsd b/framework-s/java/android/safetycenter/config/safety_center_config-v35.xsd
new file mode 100644
index 000000000..20b1e7655
--- /dev/null
+++ b/framework-s/java/android/safetycenter/config/safety_center_config-v35.xsd
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<!-- This file contains comments that define constraints that cannot be covered by the XSD language -->
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ version="1.0">
+
+ <xsd:element name="safety-center-config" type="safety-center-config"/>
+
+ <xsd:complexType name="safety-center-config">
+ <xsd:sequence>
+ <xsd:element name="safety-sources-config" type="safety-sources-config"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="safety-sources-config">
+ <xsd:sequence>
+ <xsd:element
+ name="safety-sources-group" type="safety-sources-group"
+ minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="safety-sources-group">
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element name="dynamic-safety-source" type="dynamic-safety-source"/>
+ <xsd:element name="static-safety-source" type="static-safety-source"/>
+ <xsd:element name="issue-only-safety-source" type="issue-only-safety-source"/>
+ </xsd:choice>
+ <!-- id must be unique among safety sources groups -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <!-- title is required unless the group contains issue only and/or internal sources -->
+ <xsd:attribute name="title" type="runtimeStringResourceName"/>
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <xsd:attribute name="statelessIconType" type="statelessIconTypeOrStringResourceName"
+ default="none"/>
+ <!-- type is inferred from other attributes and the group content if omitted -->
+ <xsd:attribute name="type" type="groupTypeOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="dynamic-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
+ <!-- optional comma-separated set of certificate hashes, if provided will be used for validation. -->
+ <xsd:attribute name="packageCertificateHashes" type="stringOrStringResourceName"/>
+ <!-- title is required if initialDisplayState is not set to hidden or if searchTerms are provided -->
+ <xsd:attribute name="title" type="runtimeStringResourceName"/>
+ <!-- titleForWork is required if profile is set to all_profiles, and initialDisplayState is not set to hidden or if searchTerms are provided -->
+ <!-- titleForWork is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForWork" type="runtimeStringResourceName"/>
+ <!-- titleForPrivateProfile is required if profile is set to all_profiles, and initialDisplayState is not set to hidden or if searchTerms are provided -->
+ <!-- titleForPrivateProfile is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForPrivateProfile" type="runtimeStringResourceName"/>
+ <!-- summary is required if initialDisplayState is not set to hidden -->
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <!-- intentAction is required if initialDisplayState is set to enabled -->
+ <xsd:attribute name="intentAction" type="stringOrStringResourceName"/>
+ <xsd:attribute name="profile" type="profile" use="required"/>
+ <xsd:attribute name="initialDisplayState" type="initialDisplayStateOrStringResourceName"
+ default="enabled"/>
+ <xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
+ <xsd:attribute name="searchTerms" type="runtimeStringResourceName"/>
+ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="deduplicationGroup" type="stringOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="issue-only-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName" use="required"/>
+ <!-- optional comma-separated set of certificate hashes, if provided will be used for validation. -->
+ <xsd:attribute name="packageCertificateHashes" type="stringOrStringResourceName"/>
+ <xsd:attribute name="profile" type="profileOrStringResourceName" use="required"/>
+ <xsd:attribute name="maxSeverityLevel" type="intOrStringResourceName" default="2147483647"/>
+ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/>
+ <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName"
+ default="false"/>
+ <xsd:attribute name="deduplicationGroup" type="stringOrStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="static-safety-source">
+ <!-- id must be unique among safety sources -->
+ <xsd:attribute name="id" type="idOrStringResourceName" use="required"/>
+ <xsd:attribute name="packageName" type="stringOrStringResourceName"/>
+ <xsd:attribute name="title" type="runtimeStringResourceName" use="required"/>
+ <!-- titleForWork is required if profile is set to all_profiles -->
+ <!-- titleForWork is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForWork" type="runtimeStringResourceName"/>
+ <!-- titleForPrivateProfile is required if profile is set to all_profiles -->
+ <!-- titleForPrivateProfile is prohibited if profile is set to primary_profile_only -->
+ <xsd:attribute name="titleForPrivateProfile" type="runtimeStringResourceName"/>
+ <xsd:attribute name="summary" type="runtimeStringResourceName"/>
+ <xsd:attribute name="intentAction" type="stringOrStringResourceName" use="required"/>
+ <xsd:attribute name="profile" type="profileOrStringResourceName" use="required"/>
+ <xsd:attribute name="searchTerms" type="runtimeStringResourceName"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="intOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:int. -->
+ <xsd:union memberTypes="stringResourceName xsd:int"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="booleanOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:boolean. -->
+ <xsd:union memberTypes="stringResourceName xsd:boolean"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="stringOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:string. -->
+ <xsd:union memberTypes="stringResourceName xsd:string"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="idOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type xsd:string. -->
+ <xsd:union memberTypes="stringResourceName id"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="id">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[0-9a-zA-Z_-]+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="statelessIconTypeOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type statelessIconType. -->
+ <xsd:union memberTypes="stringResourceName statelessIconType"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="statelessIconType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="none"/>
+ <xsd:enumeration value="privacy"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="profileOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type profile. -->
+ <xsd:union memberTypes="stringResourceName profile"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="profile">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="primary_profile_only"/>
+ <xsd:enumeration value="all_profiles"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="initialDisplayStateOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type initialDisplayState. -->
+ <xsd:union memberTypes="stringResourceName initialDisplayState"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="initialDisplayState">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="enabled"/>
+ <xsd:enumeration value="disabled"/>
+ <xsd:enumeration value="hidden"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="groupTypeOrStringResourceName">
+ <!-- String resource names will be resolved only once at parse time. -->
+ <!-- Locale changes and device config changes will be ignored. -->
+ <!-- The value of the string resource must be of type groupType. -->
+ <xsd:union memberTypes="stringResourceName groupType"/>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="groupType">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="stateless"/>
+ <xsd:enumeration value="stateful"/>
+ <xsd:enumeration value="hidden"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="runtimeStringResourceName">
+ <!-- String resource names will be resolved at runtime whenever the string value is used. -->
+ <xsd:union memberTypes="stringResourceName"/>
+ </xsd:simpleType>
+
+ <!-- String resource names will be ignored for any attribute not directly or indirectly marked as stringResourceName. -->
+ <!-- A stringResourceName is a fully qualified resource name of the form "@package:string/entry". Package is required. -->
+ <xsd:simpleType name="stringResourceName">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="@([a-z]+\.)*[a-z]+:string/.+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
index d485af997..7c7ade3f1 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
@@ -17,6 +17,7 @@
package com.android.safetycenter;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM;
import static com.android.safetycenter.UserProfileGroup.PROFILE_TYPE_MANAGED;
import static com.android.safetycenter.UserProfileGroup.PROFILE_TYPE_PRIMARY;
@@ -56,6 +57,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permission.flags.Flags;
import com.android.safetycenter.UserProfileGroup.ProfileType;
import com.android.safetycenter.data.SafetyCenterDataManager;
import com.android.safetycenter.internaldata.SafetyCenterBundles;
@@ -1234,8 +1236,11 @@ public final class SafetyCenterDataFactory {
safetySource.getId(),
safetySource.getTitleForWorkResId());
case PROFILE_TYPE_PRIVATE:
- //TODO(b/286539356) replace with the appropriate way to get the title when
- // available
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ return mSafetyCenterResourcesApk.getString(
+ safetySource.getTitleForPrivateProfileResId());
+ }
+ Log.w(TAG, "unsupported private profile type encountered");
return mSafetyCenterResourcesApk.getString(safetySource.getTitleResId());
default:
Log.w(TAG, "unexpected value for the profile type " + profileType);
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
index 59cc6547a..c5c5c218d 100644
--- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
+++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt
@@ -18,11 +18,13 @@ package android.safetycenter.cts.config
import android.content.res.Resources
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+import android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM
import android.safetycenter.config.SafetySource
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.truth.os.ParcelableSubject.assertThat
import androidx.test.filters.SdkSuppress
import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
import com.android.safetycenter.testing.EqualsHashCodeToStringTester
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
@@ -126,6 +128,31 @@ class SafetySourceTest {
}
}
+ @SdkSuppress(minSdkVersion = VANILLA_ICE_CREAM)
+ @Test
+ fun getTitleForPrivateProfileResId_returnsTitleForPrivateProfileResIdOrThrows() {
+ assertThrows(UnsupportedOperationException::class.java) {
+ DYNAMIC_BAREBONE.titleForPrivateProfileResId
+ }
+ assertThat(dynamicAllOptional().titleForPrivateProfileResId).isEqualTo(REFERENCE_RES_ID)
+ assertThrows(UnsupportedOperationException::class.java) {
+ DYNAMIC_DISABLED.titleForPrivateProfileResId
+ }
+ assertThat(DYNAMIC_HIDDEN.titleForPrivateProfileResId).isEqualTo(Resources.ID_NULL)
+ assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.titleForPrivateProfileResId)
+ .isEqualTo(REFERENCE_RES_ID)
+ assertThrows(UnsupportedOperationException::class.java) {
+ STATIC_BAREBONE.titleForPrivateProfileResId
+ }
+ assertThat(STATIC_ALL_OPTIONAL.titleForPrivateProfileResId).isEqualTo(REFERENCE_RES_ID)
+ assertThrows(UnsupportedOperationException::class.java) {
+ ISSUE_ONLY_BAREBONE.titleForPrivateProfileResId
+ }
+ assertThrows(UnsupportedOperationException::class.java) {
+ issueOnlyAllOptional().titleForPrivateProfileResId
+ }
+ }
+
@Test
fun getSummaryResId_returnsSummaryResIdOrThrows() {
assertThat(DYNAMIC_BAREBONE.summaryResId).isEqualTo(REFERENCE_RES_ID)
@@ -360,6 +387,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -390,6 +420,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -413,6 +446,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -436,6 +472,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -459,6 +498,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -482,6 +524,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -505,6 +550,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -536,6 +584,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -559,6 +610,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -582,6 +636,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -605,6 +662,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -628,6 +688,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
)
@@ -650,6 +713,11 @@ class SafetySourceTest {
.setNotificationsAllowed(false)
.setDeduplicationGroup(DEDUPLICATION_GROUP)
.addPackageCertificateHash(HASH1)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
)
addEqualityGroup(
@@ -669,6 +737,11 @@ class SafetySourceTest {
.setNotificationsAllowed(true)
.setDeduplicationGroup("other_deduplication_group")
.addPackageCertificateHash(HASH1)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
)
// With no package cert hashes provided
@@ -688,6 +761,11 @@ class SafetySourceTest {
.setRefreshOnPageOpenAllowed(true)
.setNotificationsAllowed(true)
.setDeduplicationGroup(DEDUPLICATION_GROUP)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
)
// With longer package cert hash list
@@ -709,6 +787,11 @@ class SafetySourceTest {
.setDeduplicationGroup(DEDUPLICATION_GROUP)
.addPackageCertificateHash(HASH1)
.addPackageCertificateHash(HASH2)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
)
// With package cert hash list with different value
@@ -729,6 +812,11 @@ class SafetySourceTest {
.setNotificationsAllowed(true)
.setDeduplicationGroup(DEDUPLICATION_GROUP)
.addPackageCertificateHash(HASH2)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
)
}
@@ -785,6 +873,9 @@ class SafetySourceTest {
setDeduplicationGroup(DEDUPLICATION_GROUP)
addPackageCertificateHash(HASH1)
}
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
}
.build()
@@ -817,6 +908,11 @@ class SafetySourceTest {
.setProfile(SafetySource.PROFILE_ALL)
.setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
.setSearchTermsResId(REFERENCE_RES_ID)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
internal val STATIC_BAREBONE =
@@ -837,6 +933,11 @@ class SafetySourceTest {
.setIntentAction(INTENT_ACTION)
.setProfile(SafetySource.PROFILE_ALL)
.setSearchTermsResId(REFERENCE_RES_ID)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(REFERENCE_RES_ID)
+ }
+ }
.build()
internal val ISSUE_ONLY_BAREBONE =
diff --git a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
index 7623af950..2eb1a6c48 100644
--- a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
+++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt
@@ -283,11 +283,7 @@ class SafetyCenterMultiUsersTest {
.safetyCenterEntryDefaultStaticBuilder(
STATIC_ALL_OPTIONAL_ID,
userId = deviceState.privateProfile().id(),
- // TODO(b/286539356): Change this to a profile specific
- // title when private profile starts reading the title from
- // the config - currently it relies on the primary profile's
- // title
- title = "OK"
+ title = "Unknown"
)
.setPendingIntent(
createTestActivityRedirectPendingIntentForUser(
@@ -325,11 +321,7 @@ class SafetyCenterMultiUsersTest {
)
private fun staticEntryForPrivateBuilder(
- // TODO(b/286539356): Change this to a profile specific
- // title when private profile starts reading the title from
- // the config - currently it relies on the primary profile's
- // title
- title: CharSequence = "OK",
+ title: CharSequence = "Unknown",
explicit: Boolean = true
) =
SafetyCenterStaticEntry.Builder(title)
@@ -949,6 +941,7 @@ class SafetyCenterMultiUsersTest {
val apiSafetyCenterData = safetyCenterManager.getSafetyCenterDataWithPermission()
val managedUserId = deviceState.workProfile().id()
+ val privateProfileId = deviceState.privateProfile().id()
val safetyCenterDataFromComplexConfig =
SafetyCenterData(
safetyCenterTestData.safetyCenterStatusCritical(11),
@@ -1004,6 +997,32 @@ class SafetyCenterMultiUsersTest {
ISSUE_ONLY_IN_STATELESS_ID,
managedUserId,
groupId = MIXED_STATELESS_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_DISABLED_ID,
+ privateProfileId,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_HIDDEN_ID,
+ privateProfileId,
+ groupId = DYNAMIC_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_ALL_OPTIONAL_ID,
+ privateProfileId,
+ attributionTitle = null,
+ groupId = ISSUE_ONLY_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ DYNAMIC_IN_STATELESS_ID,
+ privateProfileId,
+ groupId = MIXED_STATELESS_GROUP_ID
+ ),
+ safetyCenterTestData.safetyCenterIssueInformation(
+ ISSUE_ONLY_IN_STATELESS_ID,
+ privateProfileId,
+ groupId = MIXED_STATELESS_GROUP_ID
)
),
listOf(
@@ -1238,11 +1257,7 @@ class SafetyCenterMultiUsersTest {
safetyCenterTestData.safetyCenterEntryDefault(
SINGLE_SOURCE_ALL_PROFILE_ID,
deviceState.privateProfile().id(),
- // TODO(b/286539356): Change this to a profile specific
- // title when private profile starts reading the title from
- // the config - currently it relies on the primary profile's
- // title
- title = "OK",
+ title = "Unknown",
pendingIntent =
createTestActivityRedirectPendingIntentForUser(
deviceState.privateProfile().userHandle()
@@ -1259,14 +1274,14 @@ class SafetyCenterMultiUsersTest {
emptyList()
)
- // TODO(b/286539356): Add checks for the SafetyCenterData once that's adapted for the
- // private profile.
- assertThat(safetyCenterManager.getSafetyCenterDataWithPermission())
- .isEqualTo(safetyCenterDataWithPrivateProfile)
- assertThat(
- privateSafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission()
- )
- .isEqualTo(safetyCenterDataWithPrivateProfile)
+ checkState(
+ safetyCenterManager.getSafetyCenterDataWithPermission() ==
+ safetyCenterDataWithPrivateProfile
+ )
+ checkState(
+ privateSafetyCenterManager.getSafetyCenterDataWithInteractAcrossUsersPermission() ==
+ safetyCenterDataWithPrivateProfile
+ )
deviceState.privateProfile().remove()
diff --git a/tests/utils/safetycenter/Android.bp b/tests/utils/safetycenter/Android.bp
index 6accefae9..8514b0662 100644
--- a/tests/utils/safetycenter/Android.bp
+++ b/tests/utils/safetycenter/Android.bp
@@ -36,6 +36,7 @@ android_library {
"kotlinx-coroutines-android",
"safety-center-internal-data",
"safety-center-resources-lib",
+ "permissions-aconfig-flags-lib",
],
apex_available: [
"com.android.permission",
diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
index fd3749094..a4600e88b 100644
--- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
+++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestConfigs.kt
@@ -31,6 +31,7 @@ import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC
import android.safetycenter.config.SafetySourcesGroup
import androidx.annotation.RequiresApi
import com.android.modules.utils.build.SdkLevel
+import com.android.permission.flags.Flags
import com.android.safetycenter.testing.SettingsPackage.getSettingsPackageName
import java.security.MessageDigest
@@ -686,6 +687,11 @@ class SafetyCenterTestConfigs(private val context: Context) {
.setSummaryResId(Resources.ID_NULL)
.setIntentAction(null)
.setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(Resources.ID_NULL)
+ }
+ }
.build()
)
.build()
@@ -788,6 +794,11 @@ class SafetyCenterTestConfigs(private val context: Context) {
dynamicSafetySourceBuilder(id)
.setProfile(SafetySource.PROFILE_ALL)
.setTitleForWorkResId(android.R.string.paste)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(android.R.string.paste)
+ }
+ }
private fun staticSafetySource(id: String) = staticSafetySourceBuilder(id).build()
@@ -803,6 +814,11 @@ class SafetyCenterTestConfigs(private val context: Context) {
staticSafetySourceBuilder(id)
.setProfile(SafetySource.PROFILE_ALL)
.setTitleForWorkResId(android.R.string.paste)
+ .apply {
+ if (SdkLevel.isAtLeastV() && Flags.privateProfileTitleApi()) {
+ setTitleForPrivateProfileResId(android.R.string.unknownName)
+ }
+ }
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private fun issueOnlySafetySourceWithDuplicationInfo(id: String, deduplicationGroup: String) =