• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.safetycenter;
18 
19 import static android.os.Build.VERSION_CODES.TIRAMISU;
20 
21 import static com.android.internal.util.Preconditions.checkArgument;
22 
23 import static java.util.Collections.unmodifiableList;
24 import static java.util.Objects.requireNonNull;
25 
26 import android.annotation.IntDef;
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.annotation.SystemApi;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 
33 import androidx.annotation.RequiresApi;
34 
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Objects;
40 
41 /**
42  * Data class used by safety sources to propagate safety information such as their safety status and
43  * safety issues.
44  *
45  * @hide
46  */
47 @SystemApi
48 @RequiresApi(TIRAMISU)
49 public final class SafetySourceData implements Parcelable {
50 
51     /**
52      * Indicates that no opinion is currently associated with the information provided.
53      *
54      * <p>This severity level will be reflected in the UI of a {@link SafetySourceStatus} through a
55      * grey icon.
56      *
57      * <p>For a {@link SafetySourceStatus}, this severity level indicates that the safety source
58      * currently does not have sufficient information on the severity level of the {@link
59      * SafetySourceStatus}.
60      *
61      * <p>This severity level cannot be used to indicate the severity level of a {@link
62      * SafetySourceIssue}.
63      */
64     public static final int SEVERITY_LEVEL_UNSPECIFIED = 100;
65 
66     /**
67      * Indicates the presence of an informational message or the absence of any safety issues.
68      *
69      * <p>This severity level will be reflected in the UI of either a {@link SafetySourceStatus} or
70      * a {@link SafetySourceIssue} through a green icon.
71      *
72      * <p>For a {@link SafetySourceStatus}, this severity level indicates either the absence of any
73      * {@link SafetySourceIssue}s or the presence of only {@link SafetySourceIssue}s with the same
74      * severity level.
75      *
76      * <p>For a {@link SafetySourceIssue}, this severity level indicates that the {@link
77      * SafetySourceIssue} represents an informational message relating to the safety source. {@link
78      * SafetySourceIssue}s of this severity level will be dismissible by the user from the UI, and
79      * will not trigger a confirmation dialog upon a user attempting to dismiss the warning.
80      */
81     public static final int SEVERITY_LEVEL_INFORMATION = 200;
82 
83     /**
84      * Indicates the presence of a medium-severity safety issue which the user is encouraged to act
85      * on.
86      *
87      * <p>This severity level will be reflected in the UI of either a {@link SafetySourceStatus} or
88      * a {@link SafetySourceIssue} through a yellow icon.
89      *
90      * <p>For a {@link SafetySourceStatus}, this severity level indicates the presence of at least
91      * one medium-severity {@link SafetySourceIssue} relating to the safety source which the user is
92      * encouraged to act on, and no {@link SafetySourceIssue}s with higher severity level.
93      *
94      * <p>For a {@link SafetySourceIssue}, this severity level indicates that the {@link
95      * SafetySourceIssue} represents a medium-severity safety issue relating to the safety source
96      * which the user is encouraged to act on. {@link SafetySourceIssue}s of this severity level
97      * will be dismissible by the user from the UI, and will trigger a confirmation dialog upon a
98      * user attempting to dismiss the warning.
99      */
100     public static final int SEVERITY_LEVEL_RECOMMENDATION = 300;
101 
102     /**
103      * Indicates the presence of a critical or urgent safety issue that should be addressed by the
104      * user.
105      *
106      * <p>This severity level will be reflected in the UI of either a {@link SafetySourceStatus} or
107      * a {@link SafetySourceIssue} through a red icon.
108      *
109      * <p>For a {@link SafetySourceStatus}, this severity level indicates the presence of at least
110      * one critical or urgent {@link SafetySourceIssue} relating to the safety source that should be
111      * addressed by the user.
112      *
113      * <p>For a {@link SafetySourceIssue}, this severity level indicates that the {@link
114      * SafetySourceIssue} represents a critical or urgent safety issue relating to the safety source
115      * that should be addressed by the user. {@link SafetySourceIssue}s of this severity level will
116      * be dismissible by the user from the UI, and will trigger a confirmation dialog upon a user
117      * attempting to dismiss the warning.
118      */
119     public static final int SEVERITY_LEVEL_CRITICAL_WARNING = 400;
120 
121     /**
122      * All possible severity levels for a {@link SafetySourceStatus} or a {@link SafetySourceIssue}.
123      *
124      * <p>The numerical values of the levels are not used directly, rather they are used to build a
125      * continuum of levels which support relative comparison. The higher the severity level the
126      * higher the threat to the user.
127      *
128      * <p>For a {@link SafetySourceStatus}, the severity level is meant to convey the aggregated
129      * severity of the safety source, and it contributes to the overall severity level in the Safety
130      * Center. If the {@link SafetySourceData} contains {@link SafetySourceIssue}s, the severity
131      * level of the s{@link SafetySourceStatus} must match the highest severity level among the
132      * {@link SafetySourceIssue}s.
133      *
134      * <p>For a {@link SafetySourceIssue}, not all severity levels can be used. The severity level
135      * also determines how a {@link SafetySourceIssue}s is "dismissible" by the user, i.e. how the
136      * user can choose to ignore the issue and remove it from view in the Safety Center.
137      *
138      * @hide
139      */
140     @IntDef(
141             prefix = {"SEVERITY_LEVEL_"},
142             value = {
143                 SEVERITY_LEVEL_UNSPECIFIED,
144                 SEVERITY_LEVEL_INFORMATION,
145                 SEVERITY_LEVEL_RECOMMENDATION,
146                 SEVERITY_LEVEL_CRITICAL_WARNING
147             })
148     @Retention(RetentionPolicy.SOURCE)
149     public @interface SeverityLevel {}
150 
151     @NonNull
152     public static final Creator<SafetySourceData> CREATOR =
153             new Creator<SafetySourceData>() {
154                 @Override
155                 public SafetySourceData createFromParcel(Parcel in) {
156                     SafetySourceStatus status = in.readTypedObject(SafetySourceStatus.CREATOR);
157                     List<SafetySourceIssue> issues =
158                             requireNonNull(in.createTypedArrayList(SafetySourceIssue.CREATOR));
159                     Builder builder = new Builder().setStatus(status);
160                     for (int i = 0; i < issues.size(); i++) {
161                         builder.addIssue(issues.get(i));
162                     }
163                     return builder.build();
164                 }
165 
166                 @Override
167                 public SafetySourceData[] newArray(int size) {
168                     return new SafetySourceData[size];
169                 }
170             };
171 
172     @Nullable private final SafetySourceStatus mStatus;
173     @NonNull private final List<SafetySourceIssue> mIssues;
174 
SafetySourceData( @ullable SafetySourceStatus status, @NonNull List<SafetySourceIssue> issues)175     private SafetySourceData(
176             @Nullable SafetySourceStatus status, @NonNull List<SafetySourceIssue> issues) {
177         this.mStatus = status;
178         this.mIssues = issues;
179     }
180 
181     /** Returns the data for the {@link SafetySourceStatus} to be shown in UI. */
182     @Nullable
getStatus()183     public SafetySourceStatus getStatus() {
184         return mStatus;
185     }
186 
187     /** Returns the data for the list of {@link SafetySourceIssue}s to be shown in UI. */
188     @NonNull
getIssues()189     public List<SafetySourceIssue> getIssues() {
190         return mIssues;
191     }
192 
193     @Override
describeContents()194     public int describeContents() {
195         return 0;
196     }
197 
198     @Override
writeToParcel(@onNull Parcel dest, int flags)199     public void writeToParcel(@NonNull Parcel dest, int flags) {
200         dest.writeTypedObject(mStatus, flags);
201         dest.writeTypedList(mIssues);
202     }
203 
204     @Override
equals(Object o)205     public boolean equals(Object o) {
206         if (this == o) return true;
207         if (!(o instanceof SafetySourceData)) return false;
208         SafetySourceData that = (SafetySourceData) o;
209         return Objects.equals(mStatus, that.mStatus) && mIssues.equals(that.mIssues);
210     }
211 
212     @Override
hashCode()213     public int hashCode() {
214         return Objects.hash(mStatus, mIssues);
215     }
216 
217     @Override
toString()218     public String toString() {
219         return "SafetySourceData{" + ", mStatus=" + mStatus + ", mIssues=" + mIssues + '}';
220     }
221 
222     /** Builder class for {@link SafetySourceData}. */
223     public static final class Builder {
224 
225         @NonNull private final List<SafetySourceIssue> mIssues = new ArrayList<>();
226 
227         @Nullable private SafetySourceStatus mStatus;
228 
229         /** Sets data for the {@link SafetySourceStatus} to be shown in UI. */
230         @NonNull
setStatus(@ullable SafetySourceStatus status)231         public Builder setStatus(@Nullable SafetySourceStatus status) {
232             mStatus = status;
233             return this;
234         }
235 
236         /** Adds data for a {@link SafetySourceIssue} to be shown in UI. */
237         @NonNull
addIssue(@onNull SafetySourceIssue safetySourceIssue)238         public Builder addIssue(@NonNull SafetySourceIssue safetySourceIssue) {
239             mIssues.add(requireNonNull(safetySourceIssue));
240             return this;
241         }
242 
243         /**
244          * Clears data for all the {@link SafetySourceIssue}s that were added to this {@link
245          * Builder}.
246          */
247         @NonNull
clearIssues()248         public Builder clearIssues() {
249             mIssues.clear();
250             return this;
251         }
252 
253         /** Creates the {@link SafetySourceData} defined by this {@link Builder}. */
254         @NonNull
build()255         public SafetySourceData build() {
256             List<SafetySourceIssue> issues = unmodifiableList(new ArrayList<>(mIssues));
257             if (mStatus != null) {
258                 int issuesMaxSeverityLevel = getIssuesMaxSeverityLevel(issues);
259                 if (issuesMaxSeverityLevel > SafetySourceData.SEVERITY_LEVEL_INFORMATION) {
260                     checkArgument(
261                             issuesMaxSeverityLevel <= mStatus.getSeverityLevel(),
262                             "Safety source data must not contain any issue with a severity level "
263                                     + "both greater than SEVERITY_LEVEL_INFORMATION and greater "
264                                     + "than the status severity level");
265                 }
266             }
267             return new SafetySourceData(mStatus, issues);
268         }
269 
getIssuesMaxSeverityLevel(@onNull List<SafetySourceIssue> issues)270         private static int getIssuesMaxSeverityLevel(@NonNull List<SafetySourceIssue> issues) {
271             int max = Integer.MIN_VALUE;
272             for (int i = 0; i < issues.size(); i++) {
273                 max = Math.max(max, issues.get(i).getSeverityLevel());
274             }
275             return max;
276         }
277     }
278 }
279