1 /*
2  * Copyright (C) 2022 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 java.util.Collections.unmodifiableList;
22 import static java.util.Objects.requireNonNull;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SystemApi;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.safetycenter.config.SafetySourcesGroup;
30 import android.text.TextUtils;
31 
32 import androidx.annotation.RequiresApi;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 
38 /**
39  * A group of conceptually related Safety Center entries.
40  *
41  * @hide
42  */
43 @SystemApi
44 @RequiresApi(TIRAMISU)
45 public final class SafetyCenterEntryGroup implements Parcelable {
46 
47     @NonNull
48     public static final Creator<SafetyCenterEntryGroup> CREATOR =
49             new Creator<SafetyCenterEntryGroup>() {
50                 @Override
51                 public SafetyCenterEntryGroup createFromParcel(Parcel in) {
52                     String id = in.readString();
53                     CharSequence title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
54                     return new Builder(id, title)
55                             .setSummary(TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in))
56                             .setSeverityLevel(in.readInt())
57                             .setSeverityUnspecifiedIconType(in.readInt())
58                             .setEntries(in.createTypedArrayList(SafetyCenterEntry.CREATOR))
59                             .build();
60                 }
61 
62                 @Override
63                 public SafetyCenterEntryGroup[] newArray(int size) {
64                     return new SafetyCenterEntryGroup[size];
65                 }
66             };
67 
68     @NonNull private final String mId;
69     @NonNull private final CharSequence mTitle;
70     @Nullable private final CharSequence mSummary;
71     @SafetyCenterEntry.EntrySeverityLevel private final int mSeverityLevel;
72     @SafetyCenterEntry.SeverityUnspecifiedIconType private final int mSeverityUnspecifiedIconType;
73     @NonNull private final List<SafetyCenterEntry> mEntries;
74 
SafetyCenterEntryGroup( @onNull String id, @NonNull CharSequence title, @Nullable CharSequence summary, @SafetyCenterEntry.EntrySeverityLevel int severityLevel, @SafetyCenterEntry.SeverityUnspecifiedIconType int severityUnspecifiedIconType, @NonNull List<SafetyCenterEntry> entries)75     private SafetyCenterEntryGroup(
76             @NonNull String id,
77             @NonNull CharSequence title,
78             @Nullable CharSequence summary,
79             @SafetyCenterEntry.EntrySeverityLevel int severityLevel,
80             @SafetyCenterEntry.SeverityUnspecifiedIconType int severityUnspecifiedIconType,
81             @NonNull List<SafetyCenterEntry> entries) {
82         mId = id;
83         mTitle = title;
84         mSummary = summary;
85         mSeverityLevel = severityLevel;
86         mSeverityUnspecifiedIconType = severityUnspecifiedIconType;
87         mEntries = entries;
88     }
89 
90     /** Returns the ID of the {@link SafetySourcesGroup} that this group corresponds to. */
91     @NonNull
getId()92     public String getId() {
93         return mId;
94     }
95 
96     /** Returns the title of this entry group. */
97     @NonNull
getTitle()98     public CharSequence getTitle() {
99         return mTitle;
100     }
101 
102     /**
103      * Returns the summary string describing this entry group if present, or {@code null} otherwise.
104      */
105     @Nullable
getSummary()106     public CharSequence getSummary() {
107         return mSummary;
108     }
109 
110     /** Returns the combined severity level of the entries in this entry group. */
111     @SafetyCenterEntry.EntrySeverityLevel
getSeverityLevel()112     public int getSeverityLevel() {
113         return mSeverityLevel;
114     }
115 
116     /** Returns the {@link SafetyCenterEntry.SeverityUnspecifiedIconType} for this entry group. */
117     @SafetyCenterEntry.SeverityUnspecifiedIconType
getSeverityUnspecifiedIconType()118     public int getSeverityUnspecifiedIconType() {
119         return mSeverityUnspecifiedIconType;
120     }
121 
122     /** Returns the entries that comprise this entry group. */
123     @NonNull
getEntries()124     public List<SafetyCenterEntry> getEntries() {
125         return mEntries;
126     }
127 
128     @Override
equals(Object o)129     public boolean equals(Object o) {
130         if (this == o) return true;
131         if (!(o instanceof SafetyCenterEntryGroup)) return false;
132         SafetyCenterEntryGroup that = (SafetyCenterEntryGroup) o;
133         return mSeverityLevel == that.mSeverityLevel
134                 && mSeverityUnspecifiedIconType == that.mSeverityUnspecifiedIconType
135                 && Objects.equals(mId, that.mId)
136                 && TextUtils.equals(mTitle, that.mTitle)
137                 && TextUtils.equals(mSummary, that.mSummary)
138                 && Objects.equals(mEntries, that.mEntries);
139     }
140 
141     @Override
hashCode()142     public int hashCode() {
143         return Objects.hash(
144                 mId, mTitle, mSummary, mSeverityLevel, mSeverityUnspecifiedIconType, mEntries);
145     }
146 
147     @Override
toString()148     public String toString() {
149         return "SafetyCenterEntryGroup{"
150                 + "mId="
151                 + mId
152                 + ", mTitle="
153                 + mTitle
154                 + ", mSummary="
155                 + mSummary
156                 + ", mSeverityLevel="
157                 + mSeverityLevel
158                 + ", mSeverityUnspecifiedIconType="
159                 + mSeverityUnspecifiedIconType
160                 + ", mEntries="
161                 + mEntries
162                 + '}';
163     }
164 
165     @Override
describeContents()166     public int describeContents() {
167         return 0;
168     }
169 
170     @Override
writeToParcel(@onNull Parcel dest, int flags)171     public void writeToParcel(@NonNull Parcel dest, int flags) {
172         dest.writeString(mId);
173         TextUtils.writeToParcel(mTitle, dest, flags);
174         TextUtils.writeToParcel(mSummary, dest, flags);
175         dest.writeInt(mSeverityLevel);
176         dest.writeInt(mSeverityUnspecifiedIconType);
177         dest.writeTypedList(mEntries);
178     }
179 
180     /** Builder class for {@link SafetyCenterEntryGroup} */
181     public static final class Builder {
182 
183         @NonNull private String mId;
184         @NonNull private CharSequence mTitle;
185         @Nullable private CharSequence mSummary;
186 
187         @SafetyCenterEntry.EntrySeverityLevel
188         private int mSeverityLevel = SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN;
189 
190         @SafetyCenterEntry.SeverityUnspecifiedIconType
191         private int mSeverityUnspecifiedIconType =
192                 SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON;
193 
194         @NonNull private List<SafetyCenterEntry> mEntries = new ArrayList<>();
195 
196         /**
197          * Creates a {@link Builder} for a {@link SafetyCenterEntryGroup}.
198          *
199          * @param id a unique encoded string ID, see {@link #getId} for details
200          * @param title a title for this group of entries
201          */
Builder(@onNull String id, @NonNull CharSequence title)202         public Builder(@NonNull String id, @NonNull CharSequence title) {
203             mId = requireNonNull(id);
204             mTitle = requireNonNull(title);
205         }
206 
207         /**
208          * Creates a {@link Builder} with the values from the given {@link SafetyCenterEntryGroup}.
209          */
Builder(@onNull SafetyCenterEntryGroup safetyCenterEntryGroup)210         public Builder(@NonNull SafetyCenterEntryGroup safetyCenterEntryGroup) {
211             mId = safetyCenterEntryGroup.mId;
212             mTitle = safetyCenterEntryGroup.mTitle;
213             mSummary = safetyCenterEntryGroup.mSummary;
214             mSeverityLevel = safetyCenterEntryGroup.mSeverityLevel;
215             mSeverityUnspecifiedIconType = safetyCenterEntryGroup.mSeverityUnspecifiedIconType;
216             mEntries = new ArrayList<>(safetyCenterEntryGroup.mEntries);
217         }
218 
219         /** Sets the ID for this entry group. */
220         @NonNull
setId(@onNull String id)221         public Builder setId(@NonNull String id) {
222             mId = requireNonNull(id);
223             return this;
224         }
225 
226         /** Sets the title for this entry group. */
227         @NonNull
setTitle(@onNull CharSequence title)228         public Builder setTitle(@NonNull CharSequence title) {
229             mTitle = requireNonNull(title);
230             return this;
231         }
232 
233         /** Sets the optional summary text for this entry group. */
234         @NonNull
setSummary(@ullable CharSequence summary)235         public Builder setSummary(@Nullable CharSequence summary) {
236             mSummary = summary;
237             return this;
238         }
239 
240         /**
241          * Sets the {@link SafetyCenterEntry.EntrySeverityLevel} of this entry group. Defaults to
242          * {@link SafetyCenterEntry#ENTRY_SEVERITY_LEVEL_UNKNOWN}.
243          */
244         @NonNull
setSeverityLevel(@afetyCenterEntry.EntrySeverityLevel int severityLevel)245         public Builder setSeverityLevel(@SafetyCenterEntry.EntrySeverityLevel int severityLevel) {
246             mSeverityLevel = validateEntrySeverityLevel(severityLevel);
247             return this;
248         }
249 
250         /**
251          * Sets the {@link SafetyCenterEntry.SeverityUnspecifiedIconType} of this entry group.
252          * Defaults to {@link SafetyCenterEntry#SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON}.
253          */
254         @NonNull
setSeverityUnspecifiedIconType( @afetyCenterEntry.SeverityUnspecifiedIconType int severityUnspecifiedIconType)255         public Builder setSeverityUnspecifiedIconType(
256                 @SafetyCenterEntry.SeverityUnspecifiedIconType int severityUnspecifiedIconType) {
257             mSeverityUnspecifiedIconType =
258                     validateSeverityUnspecifiedIconType(severityUnspecifiedIconType);
259             return this;
260         }
261 
262         /**
263          * Sets the list of {@link SafetyCenterEntry} contained by this entry group. Defaults to an
264          * empty list.
265          */
266         @NonNull
setEntries(@onNull List<SafetyCenterEntry> entries)267         public Builder setEntries(@NonNull List<SafetyCenterEntry> entries) {
268             mEntries = requireNonNull(entries);
269             return this;
270         }
271 
272         /** Creates the {@link SafetyCenterEntryGroup} defined by this {@link Builder}. */
273         @NonNull
build()274         public SafetyCenterEntryGroup build() {
275             return new SafetyCenterEntryGroup(
276                     mId,
277                     mTitle,
278                     mSummary,
279                     mSeverityLevel,
280                     mSeverityUnspecifiedIconType,
281                     unmodifiableList(new ArrayList<>(mEntries)));
282         }
283     }
284 
285     @SafetyCenterEntry.EntrySeverityLevel
validateEntrySeverityLevel(int value)286     private static int validateEntrySeverityLevel(int value) {
287         switch (value) {
288             case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN:
289             case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED:
290             case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK:
291             case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION:
292             case SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING:
293                 return value;
294             default:
295         }
296         throw new IllegalArgumentException(
297                 "Unexpected EntrySeverityLevel for SafetyCenterEntryGroup: " + value);
298     }
299 
300     @SafetyCenterEntry.SeverityUnspecifiedIconType
validateSeverityUnspecifiedIconType(int value)301     private static int validateSeverityUnspecifiedIconType(int value) {
302         switch (value) {
303             case SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON:
304             case SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_PRIVACY:
305             case SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION:
306                 return value;
307             default:
308         }
309         throw new IllegalArgumentException(
310                 "Unexpected SeverityUnspecifiedIconType for SafetyCenterEntryGroup: " + value);
311     }
312 }
313