From 54ec16912ef9dfcca6be1789a99ebd6c034be8dd Mon Sep 17 00:00:00 2001 From: Jan Tomljanovic Date: Wed, 2 Nov 2022 16:49:41 +0000 Subject: Add API for deduplication of issues. This API allows for sources to coordinate to only show one issue, even if multiple sources are warning about the same thing. Bug: 255336335 Test: atest CtsSafetyCenterTestCases Change-Id: I5b17c1d0413f95b77a5a6c34b8e40f2a7b648689 --- .../android/safetycenter/SafetySourceIssue.java | 64 ++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'framework-s/java') diff --git a/framework-s/java/android/safetycenter/SafetySourceIssue.java b/framework-s/java/android/safetycenter/SafetySourceIssue.java index ad7a3464e..afc4f071f 100644 --- a/framework-s/java/android/safetycenter/SafetySourceIssue.java +++ b/framework-s/java/android/safetycenter/SafetySourceIssue.java @@ -161,6 +161,7 @@ public final class SafetySourceIssue implements Parcelable { builder.setNotificationBehavior(in.readInt()); builder.setAttributionTitle( TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in)); + builder.setDeduplicationId(in.readString()); } return builder.build(); } @@ -183,6 +184,7 @@ public final class SafetySourceIssue implements Parcelable { @Nullable private final Notification mCustomNotification; @NotificationBehavior private final int mNotificationBehavior; @Nullable private final CharSequence mAttributionTitle; + @Nullable private final String mDeduplicationId; private SafetySourceIssue( @NonNull String id, @@ -196,7 +198,8 @@ public final class SafetySourceIssue implements Parcelable { @NonNull String issueTypeId, @Nullable Notification customNotification, @NotificationBehavior int notificationBehavior, - @Nullable CharSequence attributionTitle) { + @Nullable CharSequence attributionTitle, + @Nullable String deduplicationId) { this.mId = id; this.mTitle = title; this.mSubtitle = subtitle; @@ -209,6 +212,7 @@ public final class SafetySourceIssue implements Parcelable { this.mCustomNotification = customNotification; this.mNotificationBehavior = notificationBehavior; this.mAttributionTitle = attributionTitle; + this.mDeduplicationId = deduplicationId; } /** @@ -371,6 +375,36 @@ public final class SafetySourceIssue implements Parcelable { return mNotificationBehavior; } + /** + * Returns the identifier used to deduplicate this issue against other issues with the same + * deduplication identifiers. + * + *

Deduplication identifier will be used to identify duplicate issues. This identifier + * applies globally across all safety sources sending data to SafetyCenter. + * + *

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 + * config). + * + *

Expected usage implies different sources will coordinate to set the same deduplication + * identifiers on issues that they want to deduplicate. + * + *

This shouldn't be a default mechanism for deduplication of issues. Most of the time + * sources should coordinate or communicate to only send the issue from one of them. That would + * also allow sources to choose which one will be displaying the issue, instead of depending on + * severity and config order. This API should only be needed if for some reason this isn't + * possible, for example, when sources can't communicate with each other and/or send issues at + * different times and/or issues can be of different severities. + */ + @Nullable + @RequiresApi(UPSIDE_DOWN_CAKE) + public String getDeduplicationId() { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + return mDeduplicationId; + } + @Override public int describeContents() { return 0; @@ -391,6 +425,7 @@ public final class SafetySourceIssue implements Parcelable { dest.writeTypedObject(mCustomNotification, flags); dest.writeInt(mNotificationBehavior); TextUtils.writeToParcel(mAttributionTitle, dest, flags); + dest.writeString(mDeduplicationId); } } @@ -410,7 +445,8 @@ public final class SafetySourceIssue implements Parcelable { && TextUtils.equals(mIssueTypeId, that.mIssueTypeId) && Objects.equals(mCustomNotification, that.mCustomNotification) && mNotificationBehavior == that.mNotificationBehavior - && TextUtils.equals(mAttributionTitle, that.mAttributionTitle); + && TextUtils.equals(mAttributionTitle, that.mAttributionTitle) + && TextUtils.equals(mDeduplicationId, that.mDeduplicationId); } @Override @@ -427,7 +463,8 @@ public final class SafetySourceIssue implements Parcelable { mIssueTypeId, mCustomNotification, mNotificationBehavior, - mAttributionTitle); + mAttributionTitle, + mDeduplicationId); } @Override @@ -457,6 +494,8 @@ public final class SafetySourceIssue implements Parcelable { + mNotificationBehavior + ", mAttributionTitle=" + mAttributionTitle + + ", mDeduplicationId=" + + mDeduplicationId + '}'; } @@ -852,6 +891,7 @@ public final class SafetySourceIssue implements Parcelable { @IssueCategory private int mIssueCategory = ISSUE_CATEGORY_GENERAL; @Nullable private PendingIntent mOnDismissPendingIntent; @Nullable private CharSequence mAttributionTitle; + @Nullable private String mDeduplicationId; @Nullable private Notification mCustomNotification = null; @@ -986,6 +1026,21 @@ public final class SafetySourceIssue implements Parcelable { return this; } + /** + * Sets the deduplication identifier for the issue. + * + * @see #getDeduplicationId() + */ + @NonNull + @RequiresApi(UPSIDE_DOWN_CAKE) + public Builder setDeduplicationId(@Nullable String deduplicationId) { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + mDeduplicationId = deduplicationId; + return this; + } + /** Creates the {@link SafetySourceIssue} defined by this {@link Builder}. */ @NonNull public SafetySourceIssue build() { @@ -1008,7 +1063,8 @@ public final class SafetySourceIssue implements Parcelable { mIssueTypeId, mCustomNotification, mNotificationBehavior, - mAttributionTitle); + mAttributionTitle, + mDeduplicationId); } } -- cgit v1.2.3-59-g8ed1b