diff options
| author | 2022-11-10 14:26:36 +0000 | |
|---|---|---|
| committer | 2022-11-17 13:40:54 +0000 | |
| commit | 51b5f99c35f8378564d3a200b86d5919d2eb6806 (patch) | |
| tree | d4a899bcee9d86f3bd5950b5c816f228c8502d73 | |
| parent | 3f25a57349eaba775bf81dbc50bdb02fa7635499 (diff) | |
Add deduplication group attribute to the SafetyCenterConfig.
Deduplication groups allow sources which are part of the same group to
deduplicate their issues.
Bug: 255334450
Test: atest CtsSafetyCenterTestCases SafetyCenterConfigTests
Change-Id: I49dad1adabf4bc639a0a298561918e2fb5962244
12 files changed, 294 insertions, 16 deletions
diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java index 5c8da1ed6..adb7260ba 100644 --- a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java +++ b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java @@ -74,6 +74,7 @@ public final class SafetyCenterConfigParser { private static final String ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED = "refreshOnPageOpenAllowed"; private static final String ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED = "notificationsAllowed"; + private static final String ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP = "deduplicationGroup"; private static final String ENUM_STATELESS_ICON_TYPE_NONE = "none"; private static final String ENUM_STATELESS_ICON_TYPE_PRIVACY = "privacy"; private static final String ENUM_PROFILE_PRIMARY = "primary_profile_only"; @@ -336,6 +337,18 @@ public final class SafetyCenterConfigParser { throw attributeUnexpected(name, parser.getAttributeName(i)); } break; + case ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP: + if (SdkLevel.isAtLeastU()) { + builder.setDeduplicationGroup( + parseStringResourceValue( + parser.getAttributeValue(i), + name, + parser.getAttributeName(i), + resources)); + } else { + throw attributeUnexpected(name, parser.getAttributeName(i)); + } + break; default: throw attributeUnexpected(name, parser.getAttributeName(i)); } 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 06c390ebc..107d6e35a 100644 --- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt +++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt @@ -76,7 +76,12 @@ class ParserConfigInvalidTest { "ConfigStaticSafetySourceWithNotifications", R.raw.config_static_safety_source_with_notifications, "Element static-safety-source invalid", - "Prohibited attribute notificationsAllowed present")) + "Prohibited attribute notificationsAllowed present"), + Params( + "ConfigStaticSafetySourceWithDeduplicationGroups", + R.raw.config_static_safety_source_with_deduplication_groups, + "Element static-safety-source invalid", + "Prohibited attribute deduplicationGroup present")) fun parametersTiramisu(): Array<Params> = arrayOf( 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 02fbb5950..34d91e6bf 100644 --- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt +++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt @@ -69,7 +69,12 @@ class ParserConfigValidTest { .setSearchTermsResId(R.string.reference) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .addSafetySource( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -85,6 +90,12 @@ class ParserConfigValidTest { .setSearchTermsResId(R.string.reference) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .addSafetySource( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -154,7 +165,12 @@ class ParserConfigValidTest { .setMaxSeverityLevel(300) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .build()) .addSafetySourcesGroup( diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml new file mode 100644 index 000000000..b75969ae1 --- /dev/null +++ b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_deduplication_groups.xml @@ -0,0 +1,32 @@ +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<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" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only" + deduplicationGroup="group"/> + </safety-sources-group> + </safety-sources-config> +</safety-center-config>
\ No newline at end of file diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml index 8d9e3aa24..eec65ec7e 100644 --- a/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml +++ b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml @@ -25,7 +25,8 @@ searchTerms="@com.android.safetycenter.config.tests:string/reference" loggingAllowed="false" refreshOnPageOpenAllowed="true" - notificationsAllowed="true"/> + notificationsAllowed="true" + deduplicationGroup="group"/> <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" @@ -38,7 +39,9 @@ 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"/> + 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"/> <dynamic-safety-source id="dynamic_disabled" packageName="package" @@ -92,7 +95,8 @@ maxSeverityLevel="300" loggingAllowed="false" refreshOnPageOpenAllowed="true" - notificationsAllowed="true"/> + notificationsAllowed="true" + deduplicationGroup="group"/> </safety-sources-group> <safety-sources-group id="mixed" diff --git a/SafetyCenter/Config/tests/res/values/strings.xml b/SafetyCenter/Config/tests/res/values/strings.xml index 195f56c2a..d7b8b13c5 100644 --- a/SafetyCenter/Config/tests/res/values/strings.xml +++ b/SafetyCenter/Config/tests/res/values/strings.xml @@ -26,4 +26,6 @@ <string name="dynamic_all_references_max_severity_level" translatable="false">300</string> <string name="dynamic_all_references_logging_allowed" translatable="false">false</string> <string name="dynamic_all_references_refresh_on_page_open_allowed" translatable="false">true</string> + <string name="dynamic_all_references_notifications_allowed" translatable="false">true</string> + <string name="dynamic_all_references_deduplication_group" translatable="false">group</string> </resources> diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt index 8529f0eee..887d3fec7 100644 --- a/framework-s/api/system-current.txt +++ b/framework-s/api/system-current.txt @@ -479,6 +479,7 @@ package android.safetycenter.config { public final class SafetySource implements android.os.Parcelable { method public boolean areNotificationsAllowed(); method public int describeContents(); + method @Nullable public String getDeduplicationGroup(); method @NonNull public String getId(); method public int getInitialDisplayState(); method @Nullable public String getIntentAction(); @@ -508,6 +509,7 @@ package android.safetycenter.config { public static final class SafetySource.Builder { ctor public SafetySource.Builder(int); method @NonNull public android.safetycenter.config.SafetySource build(); + method @NonNull public android.safetycenter.config.SafetySource.Builder setDeduplicationGroup(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setId(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setInitialDisplayState(int); method @NonNull public android.safetycenter.config.SafetySource.Builder setIntentAction(@Nullable String); diff --git a/framework-s/java/android/safetycenter/SafetySourceIssue.java b/framework-s/java/android/safetycenter/SafetySourceIssue.java index afc4f071f..f4a369a4b 100644 --- a/framework-s/java/android/safetycenter/SafetySourceIssue.java +++ b/framework-s/java/android/safetycenter/SafetySourceIssue.java @@ -380,7 +380,10 @@ public final class SafetySourceIssue implements Parcelable { * deduplication identifiers. * * <p>Deduplication identifier will be used to identify duplicate issues. This identifier - * applies globally across all safety sources sending data to SafetyCenter. + * applies across all safety sources which are part of the same deduplication group. + * Deduplication groups can be set, for each source, in the SafetyCenter config. Therefore, two + * issues are considered duplicate if their sources are part of the same deduplication group and + * they have the same deduplication identifier. * * <p>Out of all issues that are found to be duplicates, only one will be shown in the UI (the * one with the highest severity, or in case of same severities, the one placed highest in the diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java index 9c8c279c3..d3d9cb9f7 100644 --- a/framework-s/java/android/safetycenter/config/SafetySource.java +++ b/framework-s/java/android/safetycenter/config/SafetySource.java @@ -171,6 +171,7 @@ public final class SafetySource implements Parcelable { .setRefreshOnPageOpenAllowed(in.readBoolean()); if (SdkLevel.isAtLeastU()) { builder.setNotificationsAllowed(in.readBoolean()); + builder.setDeduplicationGroup(in.readString()); } return builder.build(); } @@ -195,6 +196,7 @@ public final class SafetySource implements Parcelable { private final boolean mLoggingAllowed; private final boolean mRefreshOnPageOpenAllowed; private final boolean mNotificationsAllowed; + @Nullable final String mDeduplicationGroup; private SafetySource( @SafetySourceType int type, @@ -210,7 +212,8 @@ public final class SafetySource implements Parcelable { @StringRes int searchTermsResId, boolean loggingAllowed, boolean refreshOnPageOpenAllowed, - boolean notificationsAllowed) { + boolean notificationsAllowed, + @Nullable String deduplicationGroup) { mType = type; mId = id; mPackageName = packageName; @@ -225,6 +228,7 @@ public final class SafetySource implements Parcelable { mLoggingAllowed = loggingAllowed; mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed; mNotificationsAllowed = notificationsAllowed; + mDeduplicationGroup = deduplicationGroup; } /** Returns the type of this safety source. */ @@ -442,6 +446,21 @@ public final class SafetySource implements Parcelable { return mNotificationsAllowed; } + /** + * Returns the deduplication group this source belongs to. + * + * <p>Sources which are part of the same deduplication group can coordinate to deduplicate their + * issues. + */ + @Nullable + @RequiresApi(UPSIDE_DOWN_CAKE) + public String getDeduplicationGroup() { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + return mDeduplicationGroup; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -460,7 +479,8 @@ public final class SafetySource implements Parcelable { && mSearchTermsResId == that.mSearchTermsResId && mLoggingAllowed == that.mLoggingAllowed && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed - && mNotificationsAllowed == that.mNotificationsAllowed; + && mNotificationsAllowed == that.mNotificationsAllowed + && Objects.equals(mDeduplicationGroup, that.mDeduplicationGroup); } @Override @@ -479,7 +499,8 @@ public final class SafetySource implements Parcelable { mSearchTermsResId, mLoggingAllowed, mRefreshOnPageOpenAllowed, - mNotificationsAllowed); + mNotificationsAllowed, + mDeduplicationGroup); } @Override @@ -513,6 +534,8 @@ public final class SafetySource implements Parcelable { + mRefreshOnPageOpenAllowed + ", mNotificationsAllowed=" + mNotificationsAllowed + + ", mDeduplicationGroup=" + + mDeduplicationGroup + '}'; } @@ -538,6 +561,7 @@ public final class SafetySource implements Parcelable { dest.writeBoolean(mRefreshOnPageOpenAllowed); if (SdkLevel.isAtLeastU()) { dest.writeBoolean(mNotificationsAllowed); + dest.writeString(mDeduplicationGroup); } } @@ -558,6 +582,7 @@ public final class SafetySource implements Parcelable { @Nullable private Boolean mLoggingAllowed; @Nullable private Boolean mRefreshOnPageOpenAllowed; @Nullable private Boolean mNotificationsAllowed; + @Nullable private String mDeduplicationGroup; /** Creates a {@link Builder} for a {@link SafetySource}. */ public Builder(@SafetySourceType int type) { @@ -766,6 +791,25 @@ public final class SafetySource implements Parcelable { } /** + * Sets the deduplication group for this source. + * + * <p>Sources which are part of the same deduplication group can coordinate to deduplicate + * issues that they're sending to SafetyCenter by providing the same deduplication + * identifier with those issues. + * + * <p>The deduplication group property is prohibited for sources of type static. + */ + @NonNull + @RequiresApi(UPSIDE_DOWN_CAKE) + public Builder setDeduplicationGroup(@Nullable String deduplicationGroup) { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + mDeduplicationGroup = deduplicationGroup; + return this; + } + + /** * Creates the {@link SafetySource} defined by this {@link Builder}. * * <p>Throws an {@link IllegalStateException} if any constraint on the safety source is @@ -868,6 +912,9 @@ public final class SafetySource implements Parcelable { false, isStatic, false); + + BuilderUtils.validateAttribute( + mDeduplicationGroup, "deduplicationGroup", false, isStatic); } return new SafetySource( @@ -884,7 +931,8 @@ public final class SafetySource implements Parcelable { searchTermsResId, loggingAllowed, refreshOnPageOpenAllowed, - notificationsAllowed); + notificationsAllowed, + mDeduplicationGroup); } } } diff --git a/framework-s/java/android/safetycenter/config/safety_center_config.xsd b/framework-s/java/android/safetycenter/config/safety_center_config.xsd index 8d9903e16..75b31c166 100644 --- a/framework-s/java/android/safetycenter/config/safety_center_config.xsd +++ b/framework-s/java/android/safetycenter/config/safety_center_config.xsd @@ -72,6 +72,7 @@ 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"> @@ -85,6 +86,7 @@ default="false"/> <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName" default="false"/> + <xsd:attribute name="deduplicationGroup" type="stringOrStringResourceName"/> </xsd:complexType> <xsd:complexType name="static-safety-source"> 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 60a14794b..393ae38c1 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt @@ -259,6 +259,20 @@ class SafetySourceTest { assertThat(issueOnlyAllOptional().areNotificationsAllowed()).isTrue() } + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake") + @Test + fun getDeduplicationGroupsList_returnsDeduplicationGroups() { + assertThat(DYNAMIC_BAREBONE.deduplicationGroup).isNull() + assertThat(dynamicAllOptional().deduplicationGroup).isEqualTo(DEDUPLICATION_GROUP) + assertThat(DYNAMIC_DISABLED.deduplicationGroup).isNull() + assertThat(DYNAMIC_HIDDEN.deduplicationGroup).isNull() + assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.deduplicationGroup).isNull() + assertThat(STATIC_BAREBONE.deduplicationGroup).isNull() + assertThat(STATIC_ALL_OPTIONAL.deduplicationGroup).isNull() + assertThat(ISSUE_ONLY_BAREBONE.deduplicationGroup).isNull() + assertThat(issueOnlyAllOptional().deduplicationGroup).isEqualTo(DEDUPLICATION_GROUP) + } + @Test fun describeContents_returns0() { assertThat(DYNAMIC_BAREBONE.describeContents()).isEqualTo(0) @@ -304,7 +318,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup(DYNAMIC_HIDDEN) .addEqualityGroup(DYNAMIC_HIDDEN_WITH_SEARCH) @@ -327,7 +346,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -343,6 +367,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -358,6 +388,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -373,6 +409,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -388,6 +430,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -403,6 +451,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -410,7 +464,6 @@ class SafetySourceTest { .setPackageName(PACKAGE_NAME) .setProfile(SafetySource.PROFILE_PRIMARY) .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_HIDDEN) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -426,6 +479,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -441,6 +500,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -456,6 +521,12 @@ class SafetySourceTest { .setSearchTermsResId(-1) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -471,6 +542,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(true) .setRefreshOnPageOpenAllowed(true) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -486,7 +563,51 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(false) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build()) + .apply { + if (SdkLevel.isAtLeastU()) { + addEqualityGroup( + SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) + .setId(DYNAMIC_ALL_OPTIONAL_ID) + .setPackageName(PACKAGE_NAME) + .setTitleResId(REFERENCE_RES_ID) + .setTitleForWorkResId(REFERENCE_RES_ID) + .setSummaryResId(REFERENCE_RES_ID) + .setIntentAction(INTENT_ACTION) + .setProfile(SafetySource.PROFILE_ALL) + .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED) + .setMaxSeverityLevel(MAX_SEVERITY_LEVEL) + .setSearchTermsResId(REFERENCE_RES_ID) + .setLoggingAllowed(false) + .setRefreshOnPageOpenAllowed(true) + .setNotificationsAllowed(false) + .setDeduplicationGroup(DEDUPLICATION_GROUP) + .build()) + addEqualityGroup( + SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) + .setId(DYNAMIC_ALL_OPTIONAL_ID) + .setPackageName(PACKAGE_NAME) + .setTitleResId(REFERENCE_RES_ID) + .setTitleForWorkResId(REFERENCE_RES_ID) + .setSummaryResId(REFERENCE_RES_ID) + .setIntentAction(INTENT_ACTION) + .setProfile(SafetySource.PROFILE_ALL) + .setInitialDisplayState(SafetySource.INITIAL_DISPLAY_STATE_DISABLED) + .setMaxSeverityLevel(MAX_SEVERITY_LEVEL) + .setSearchTermsResId(REFERENCE_RES_ID) + .setLoggingAllowed(false) + .setRefreshOnPageOpenAllowed(true) + .setNotificationsAllowed(true) + .setDeduplicationGroup("other_deduplication_group") + .build()) + } + } .test() } @@ -505,6 +626,7 @@ class SafetySourceTest { private const val STATIC_ALL_OPTIONAL_ID = "static_all_optional" private const val ISSUE_ONLY_BAREBONE_ID = "issue_only_barebone" private const val ISSUE_ONLY_ALL_OPTIONAL_ID = "issue_only_all_optional" + private const val DEDUPLICATION_GROUP = "deduplication_group" internal val DYNAMIC_BAREBONE = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -530,7 +652,12 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build() private val DYNAMIC_DISABLED = @@ -598,7 +725,12 @@ class SafetySourceTest { .setMaxSeverityLevel(MAX_SEVERITY_LEVEL) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) - .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup(DEDUPLICATION_GROUP) + } + } .build() } } diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterCtsConfigs.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterCtsConfigs.kt index ab5db20e2..359420f5b 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterCtsConfigs.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterCtsConfigs.kt @@ -26,6 +26,7 @@ import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY import android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC import android.safetycenter.config.SafetySourcesGroup import android.safetycenter.cts.testing.SettingsPackage.getSettingsPackageName +import com.android.modules.utils.build.SdkLevel /** * A class that provides [SafetyCenterConfig] objects and associated constants to facilitate setting @@ -508,6 +509,12 @@ object SafetyCenterCtsConfigs { .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION) .setSearchTermsResId(android.R.string.ok) .setLoggingAllowed(false) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .addSafetySource( dynamicSafetySourceBuilder(DYNAMIC_DISABLED_ID) @@ -553,6 +560,12 @@ object SafetyCenterCtsConfigs { issueOnlySafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID) .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION) .setLoggingAllowed(false) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .build()) .addSafetySourcesGroup( @@ -618,6 +631,12 @@ object SafetyCenterCtsConfigs { issueOnlyAllProfileSafetySourceBuilder(ISSUE_ONLY_ALL_OPTIONAL_ID) .setMaxSeverityLevel(SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION) .setLoggingAllowed(false) + .apply { + if (SdkLevel.isAtLeastU()) { + setNotificationsAllowed(true) + setDeduplicationGroup("group") + } + } .build()) .build()) .addSafetySourcesGroup( |