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