summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Manish Singh <psych@google.com> 2024-01-17 15:42:04 +0000
committer Manish Singh <psych@google.com> 2024-02-08 09:58:40 +0000
commit1103d313bf297370cd948cf4a78d4a3f748ba87e (patch)
tree0567393667ee76bd0b35a324043324bd87f03f9d
parent48618644f8e98d2df80ae95ec3e8ebfc00139afb (diff)
Add the titleForPrivateProfile API
This API lets the safety sources set the title for the private profile in the safety center config file. This change also temporarily disables the linter. Safety Center team will look into enabling it later. Bug: 286539356 Test: manual Change-Id: I99ab006240883065d290b2d9976f2a7c9bf7905e
-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) =