• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import androidx.annotation.RequiresApi;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.Objects;
33 
34 /**
35  * A safety event that may trigger a safety source to set its {@link SafetySourceData}.
36  *
37  * @hide
38  */
39 @SystemApi
40 @RequiresApi(TIRAMISU)
41 public final class SafetyEvent implements Parcelable {
42 
43     /**
44      * Indicates that there has been a change of state for safety source, which may be independent
45      * of Safety Center interactions.
46      */
47     public static final int SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED = 100;
48 
49     /**
50      * Indicates that the safety source performed a data refresh in response to a request from
51      * Safety Center.
52      */
53     public static final int SAFETY_EVENT_TYPE_REFRESH_REQUESTED = 200;
54 
55     /**
56      * Indicates that the safety source successfully completed a resolving {@link
57      * SafetySourceIssue.Action}.
58      */
59     public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED = 300;
60 
61     /**
62      * Indicates that the safety source failed to complete a resolving {@link
63      * SafetySourceIssue.Action}.
64      */
65     public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED = 400;
66 
67     /** Indicates that the device's locale changed. */
68     public static final int SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED = 500;
69 
70     /** Indicates that the device was rebooted. */
71     public static final int SAFETY_EVENT_TYPE_DEVICE_REBOOTED = 600;
72 
73     /**
74      * Types of safety events that may trigger a set of a safety source's {@link SafetySourceData}.
75      *
76      * @hide
77      */
78     @IntDef(
79             prefix = {"SAFETY_EVENT_TYPE_"},
80             value = {
81                 SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED,
82                 SAFETY_EVENT_TYPE_REFRESH_REQUESTED,
83                 SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED,
84                 SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED,
85                 SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED,
86                 SAFETY_EVENT_TYPE_DEVICE_REBOOTED
87             })
88     @Retention(RetentionPolicy.SOURCE)
89     public @interface Type {}
90 
91     @NonNull
92     public static final Creator<SafetyEvent> CREATOR =
93             new Creator<SafetyEvent>() {
94                 @Override
95                 public SafetyEvent createFromParcel(Parcel in) {
96                     int type = in.readInt();
97                     return new SafetyEvent.Builder(type)
98                             .setRefreshBroadcastId(in.readString())
99                             .setSafetySourceIssueId(in.readString())
100                             .setSafetySourceIssueActionId(in.readString())
101                             .build();
102                 }
103 
104                 @Override
105                 public SafetyEvent[] newArray(int size) {
106                     return new SafetyEvent[size];
107                 }
108             };
109 
110     @Type private final int mType;
111     @Nullable private final String mRefreshBroadcastId;
112     @Nullable private final String mSafetySourceIssueId;
113     @Nullable private final String mSafetySourceIssueActionId;
114 
SafetyEvent( @ype int type, @Nullable String refreshBroadcastId, @Nullable String safetySourceIssueId, @Nullable String safetySourceIssueActionId)115     private SafetyEvent(
116             @Type int type,
117             @Nullable String refreshBroadcastId,
118             @Nullable String safetySourceIssueId,
119             @Nullable String safetySourceIssueActionId) {
120         mType = type;
121         mRefreshBroadcastId = refreshBroadcastId;
122         mSafetySourceIssueId = safetySourceIssueId;
123         mSafetySourceIssueActionId = safetySourceIssueActionId;
124     }
125 
126     /** Returns the type of the safety event. */
127     @Type
getType()128     public int getType() {
129         return mType;
130     }
131 
132     /**
133      * Returns an optional id provided by Safety Center when requesting a refresh, through {@link
134      * SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID}.
135      *
136      * <p>This will only be relevant for events of type {@link
137      * #SAFETY_EVENT_TYPE_REFRESH_REQUESTED}.
138      *
139      * @see #getType()
140      */
141     @Nullable
getRefreshBroadcastId()142     public String getRefreshBroadcastId() {
143         return mRefreshBroadcastId;
144     }
145 
146     /**
147      * Returns the id of the {@link SafetySourceIssue} this event is associated with (if any).
148      *
149      * <p>This will only be relevant for events of type {@link
150      * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or {@link
151      * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}.
152      *
153      * @see #getType()
154      * @see SafetySourceIssue#getId()
155      */
156     @Nullable
getSafetySourceIssueId()157     public String getSafetySourceIssueId() {
158         return mSafetySourceIssueId;
159     }
160 
161     /**
162      * Returns the id of the {@link SafetySourceIssue.Action} this event is associated with (if
163      * any).
164      *
165      * <p>This will only be relevant for events of type {@link
166      * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or {@link
167      * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}.
168      *
169      * @see #getType()
170      * @see SafetySourceIssue.Action#getId()
171      */
172     @Nullable
getSafetySourceIssueActionId()173     public String getSafetySourceIssueActionId() {
174         return mSafetySourceIssueActionId;
175     }
176 
177     @Override
describeContents()178     public int describeContents() {
179         return 0;
180     }
181 
182     @Override
writeToParcel(@onNull Parcel dest, int flags)183     public void writeToParcel(@NonNull Parcel dest, int flags) {
184         dest.writeInt(mType);
185         dest.writeString(mRefreshBroadcastId);
186         dest.writeString(mSafetySourceIssueId);
187         dest.writeString(mSafetySourceIssueActionId);
188     }
189 
190     @Override
equals(Object o)191     public boolean equals(Object o) {
192         if (this == o) return true;
193         if (!(o instanceof SafetyEvent)) return false;
194         SafetyEvent that = (SafetyEvent) o;
195         return mType == that.mType
196                 && Objects.equals(mRefreshBroadcastId, that.mRefreshBroadcastId)
197                 && Objects.equals(mSafetySourceIssueId, that.mSafetySourceIssueId)
198                 && Objects.equals(mSafetySourceIssueActionId, that.mSafetySourceIssueActionId);
199     }
200 
201     @Override
hashCode()202     public int hashCode() {
203         return Objects.hash(
204                 mType, mRefreshBroadcastId, mSafetySourceIssueId, mSafetySourceIssueActionId);
205     }
206 
207     @Override
toString()208     public String toString() {
209         return "SafetyEvent{"
210                 + "mType="
211                 + mType
212                 + ", mRefreshBroadcastId='"
213                 + mRefreshBroadcastId
214                 + '\''
215                 + ", mSafetySourceIssueId='"
216                 + mSafetySourceIssueId
217                 + '\''
218                 + ", mSafetySourceIssueActionId='"
219                 + mSafetySourceIssueActionId
220                 + '\''
221                 + '}';
222     }
223 
224     /** Builder class for {@link SafetyEvent}. */
225     public static final class Builder {
226 
227         @Type private final int mType;
228         @Nullable private String mRefreshBroadcastId;
229         @Nullable private String mSafetySourceIssueId;
230         @Nullable private String mSafetySourceIssueActionId;
231 
232         /** Creates a {@link Builder} for {@link SafetyEvent}. */
Builder(@ype int type)233         public Builder(@Type int type) {
234             mType = validateType(type);
235         }
236 
237         /**
238          * Sets an optional broadcast id provided by Safety Center when requesting a refresh,
239          * through {@link SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID}.
240          *
241          * <p>This will only be relevant for events of type {@link
242          * #SAFETY_EVENT_TYPE_REFRESH_REQUESTED}.
243          *
244          * @see #getType()
245          */
246         @NonNull
setRefreshBroadcastId(@ullable String refreshBroadcastId)247         public Builder setRefreshBroadcastId(@Nullable String refreshBroadcastId) {
248             mRefreshBroadcastId = refreshBroadcastId;
249             return this;
250         }
251 
252         /**
253          * Sets the id of the {@link SafetySourceIssue} this event is associated with (if any).
254          *
255          * <p>This will only be relevant for events of type {@link
256          * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or {@link
257          * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}.
258          *
259          * @see #getType()
260          * @see SafetySourceIssue#getId()
261          */
262         @NonNull
setSafetySourceIssueId(@ullable String safetySourceIssueId)263         public Builder setSafetySourceIssueId(@Nullable String safetySourceIssueId) {
264             mSafetySourceIssueId = safetySourceIssueId;
265             return this;
266         }
267 
268         /**
269          * Sets the id of the {@link SafetySourceIssue.Action} this event is associated with (if
270          * any).
271          *
272          * <p>This will only be relevant for events of type {@link
273          * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or {@link
274          * #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}.
275          *
276          * @see #getType()
277          * @see SafetySourceIssue.Action#getId()
278          */
279         @NonNull
setSafetySourceIssueActionId(@ullable String safetySourceIssueActionId)280         public Builder setSafetySourceIssueActionId(@Nullable String safetySourceIssueActionId) {
281             mSafetySourceIssueActionId = safetySourceIssueActionId;
282             return this;
283         }
284 
285         /** Creates the {@link SafetyEvent} represented by this {@link Builder}. */
286         @NonNull
build()287         public SafetyEvent build() {
288             switch (mType) {
289                 case SAFETY_EVENT_TYPE_REFRESH_REQUESTED:
290                     if (mRefreshBroadcastId == null) {
291                         throw new IllegalArgumentException(
292                                 "Missing refresh broadcast id for refresh requested safety event");
293                     }
294                     break;
295                 case SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED:
296                 case SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED:
297                     if (mSafetySourceIssueId == null) {
298                         throw new IllegalArgumentException(
299                                 String.format(
300                                         "Missing issue id for resolving action safety event (%s)",
301                                         mType));
302                     }
303                     if (mSafetySourceIssueActionId == null) {
304                         throw new IllegalArgumentException(
305                                 String.format(
306                                         "Missing issue action id for resolving action safety event "
307                                                 + "(%s)",
308                                         mType));
309                     }
310                     break;
311                 case SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED:
312                 case SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED:
313                 case SAFETY_EVENT_TYPE_DEVICE_REBOOTED:
314                 default:
315             }
316             return new SafetyEvent(
317                     mType, mRefreshBroadcastId, mSafetySourceIssueId, mSafetySourceIssueActionId);
318         }
319     }
320 
321     @Type
validateType(int value)322     private static int validateType(int value) {
323         switch (value) {
324             case SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED:
325             case SAFETY_EVENT_TYPE_REFRESH_REQUESTED:
326             case SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED:
327             case SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED:
328             case SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED:
329             case SAFETY_EVENT_TYPE_DEVICE_REBOOTED:
330                 return value;
331             default:
332         }
333         throw new IllegalArgumentException(
334                 String.format("Unexpected Type for SafetyEvent: %s", value));
335     }
336 }
337