• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 com.android.safetycenter.logging;
18 
19 import static android.os.Build.VERSION_CODES.TIRAMISU;
20 
21 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED;
22 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED;
23 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
24 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED;
25 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED;
26 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE;
27 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN;
28 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
29 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
30 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN;
31 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
32 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
33 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
34 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
35 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION;
36 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED;
37 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
38 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
39 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
40 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION;
41 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
42 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
43 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
44 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS;
45 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT;
46 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
47 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
48 import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN;
49 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED;
50 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
51 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED;
52 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED;
53 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
54 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
55 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
56 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
57 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
58 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
59 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED;
60 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED;
61 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_ERROR;
62 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT;
63 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED;
64 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR;
65 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN;
66 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
67 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
68 import static com.android.permission.PermissionStatsLog.SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
69 import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
70 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
71 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
72 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
73 import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
74 
75 import android.annotation.ElapsedRealtimeLong;
76 import android.annotation.IntDef;
77 import android.annotation.Nullable;
78 import android.safetycenter.SafetyCenterManager;
79 import android.safetycenter.SafetyCenterManager.RefreshRequestType;
80 import android.safetycenter.SafetyCenterStatus;
81 import android.safetycenter.SafetyEvent;
82 import android.safetycenter.SafetySourceData;
83 import android.util.Log;
84 import android.util.StatsEvent;
85 
86 import androidx.annotation.RequiresApi;
87 
88 import com.android.permission.PermissionStatsLog;
89 import com.android.safetycenter.SafetyCenterFlags;
90 
91 import java.lang.annotation.Retention;
92 import java.lang.annotation.RetentionPolicy;
93 import java.math.BigInteger;
94 import java.security.MessageDigest;
95 import java.security.NoSuchAlgorithmException;
96 import java.time.Duration;
97 
98 /**
99  * Marshalls and writes statsd atoms. Contains implementation details of how atom parameters are
100  * encoded and provides a better-typed interface for other classes to call.
101  *
102  * @hide
103  */
104 @RequiresApi(TIRAMISU)
105 public final class SafetyCenterStatsdLogger {
106 
107     private static final String TAG = "SafetyCenterStatsdLog";
108     private static final long UNSET_SOURCE_ID = 0;
109     private static final long UNSET_ISSUE_TYPE_ID = 0;
110     private static final long UNSET_SESSION_ID = 0;
111     private static final long UNSET_SOURCE_GROUP_ID = 0;
112     private static final long UNSET_REFRESH_REASON = 0L;
113     private static final boolean UNSET_DATA_CHANGED = false;
114     private static final long UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS = 0L;
115 
116     /**
117      * The different results for a system event reported by Safety Center.
118      *
119      * @hide
120      */
121     @IntDef(
122             prefix = {"SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__"},
123             value = {
124                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS,
125                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR,
126                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT
127             })
128     @Retention(RetentionPolicy.SOURCE)
129     public @interface SystemEventResult {}
130 
131     /**
132      * The different results for a system event reported by Safety Center.
133      *
134      * @hide
135      */
136     @IntDef(
137             prefix = {"SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__"},
138             value = {
139                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_STATE_UNKNOWN,
140                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__DATA_PROVIDED,
141                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__NO_DATA_PROVIDED,
142                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_TIMEOUT,
143                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__REFRESH_ERROR,
144                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_ERROR,
145                 SAFETY_SOURCE_STATE_COLLECTED__SOURCE_STATE__SOURCE_CLEARED
146             })
147     @Retention(RetentionPolicy.SOURCE)
148     public @interface SourceState {}
149 
150     /**
151      * Creates a {@link PermissionStatsLog#SAFETY_STATE} {@link StatsEvent} with the given
152      * parameters.
153      */
createSafetyStateEvent( @afetyCenterStatus.OverallSeverityLevel int severityLevel, long openIssueCount, long dismissedIssueCount)154     static StatsEvent createSafetyStateEvent(
155             @SafetyCenterStatus.OverallSeverityLevel int severityLevel,
156             long openIssueCount,
157             long dismissedIssueCount) {
158         return PermissionStatsLog.buildStatsEvent(
159                 SAFETY_STATE,
160                 toSafetyStateOverallSeverityLevel(severityLevel),
161                 openIssueCount,
162                 dismissedIssueCount);
163     }
164 
165     /** Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom. */
writeSafetySourceStateCollected( String sourceId, boolean isManagedProfile, @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel, long openIssuesCount, long dismissedIssuesCount, long duplicateFilteredOutIssuesCount, @SourceState int sourceState, @Nullable SafetyEvent safetyEvent, @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason, boolean dataChanged, @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis)166     public static void writeSafetySourceStateCollected(
167             String sourceId,
168             boolean isManagedProfile,
169             @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
170             long openIssuesCount,
171             long dismissedIssuesCount,
172             long duplicateFilteredOutIssuesCount,
173             @SourceState int sourceState,
174             @Nullable SafetyEvent safetyEvent,
175             @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
176             boolean dataChanged,
177             @Nullable @ElapsedRealtimeLong Long lastUpdatedElapsedTimeMillis) {
178         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
179             return;
180         }
181         int collectionType =
182                 safetyEvent != null
183                         ? SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED
184                         : SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
185         PermissionStatsLog.write(
186                 SAFETY_SOURCE_STATE_COLLECTED,
187                 idStringToLong(sourceId),
188                 toSourceStateCollectedProfileType(isManagedProfile),
189                 toSafetySourceStateCollectedSeverityLevel(sourceSeverityLevel),
190                 openIssuesCount,
191                 dismissedIssuesCount,
192                 duplicateFilteredOutIssuesCount,
193                 sourceState,
194                 collectionType,
195                 toSafetySourceStateCollectedCollectionType(safetyEvent),
196                 refreshReason != null ? refreshReason : UNSET_REFRESH_REASON,
197                 dataChanged,
198                 lastUpdatedElapsedTimeMillis != null
199                         ? lastUpdatedElapsedTimeMillis
200                         : UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS);
201     }
202 
203     /**
204      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
205      * SINGLE_SOURCE_RESCAN} or {@code SINGLE_SOURCE_GET_DATA}.
206      */
writeSourceRefreshSystemEvent( @efreshRequestType int refreshType, String sourceId, boolean isManagedProfile, Duration duration, @SystemEventResult int result, long refreshReason, boolean dataChanged)207     public static void writeSourceRefreshSystemEvent(
208             @RefreshRequestType int refreshType,
209             String sourceId,
210             boolean isManagedProfile,
211             Duration duration,
212             @SystemEventResult int result,
213             long refreshReason,
214             boolean dataChanged) {
215         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
216             return;
217         }
218         PermissionStatsLog.write(
219                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
220                 toSourceRefreshEventType(refreshType),
221                 idStringToLong(sourceId),
222                 toSystemEventProfileType(isManagedProfile),
223                 UNSET_ISSUE_TYPE_ID,
224                 duration.toMillis(),
225                 result,
226                 refreshReason,
227                 dataChanged);
228     }
229 
230     /**
231      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
232      * COMPLETE_RESCAN} or {@code COMPLETE_GET_DATA}.
233      */
writeWholeRefreshSystemEvent( @efreshRequestType int refreshType, Duration duration, @SystemEventResult int result, long refreshReason, boolean dataChanged)234     public static void writeWholeRefreshSystemEvent(
235             @RefreshRequestType int refreshType,
236             Duration duration,
237             @SystemEventResult int result,
238             long refreshReason,
239             boolean dataChanged) {
240         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
241             return;
242         }
243         PermissionStatsLog.write(
244                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
245                 toWholeRefreshEventType(refreshType),
246                 UNSET_SOURCE_ID,
247                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_UNKNOWN,
248                 UNSET_ISSUE_TYPE_ID,
249                 duration.toMillis(),
250                 result,
251                 refreshReason,
252                 dataChanged);
253     }
254 
255     /**
256      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_SYSTEM_EVENT_REPORTED} atom of type {@code
257      * INLINE_ACTION}.
258      */
writeInlineActionSystemEvent( String sourceId, boolean isManagedProfile, @Nullable String issueTypeId, Duration duration, @SystemEventResult int result)259     public static void writeInlineActionSystemEvent(
260             String sourceId,
261             boolean isManagedProfile,
262             @Nullable String issueTypeId,
263             Duration duration,
264             @SystemEventResult int result) {
265         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
266             return;
267         }
268         PermissionStatsLog.write(
269                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED,
270                 SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__INLINE_ACTION,
271                 idStringToLong(sourceId),
272                 toSystemEventProfileType(isManagedProfile),
273                 issueTypeId == null ? UNSET_ISSUE_TYPE_ID : idStringToLong(issueTypeId),
274                 duration.toMillis(),
275                 result,
276                 UNSET_REFRESH_REASON,
277                 UNSET_DATA_CHANGED);
278     }
279 
280     /**
281      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
282      * {@code NOTIFICATION_POSTED}.
283      */
writeNotificationPostedEvent( String sourceId, boolean isManagedProfile, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)284     public static void writeNotificationPostedEvent(
285             String sourceId,
286             boolean isManagedProfile,
287             String issueTypeId,
288             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
289         writeNotificationInteractionReportedEvent(
290                 SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_POSTED,
291                 sourceId,
292                 isManagedProfile,
293                 issueTypeId,
294                 sourceSeverityLevel);
295     }
296 
297     /**
298      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
299      * {@code NOTIFICATION_DISMISSED}.
300      */
writeNotificationDismissedEvent( String sourceId, boolean isManagedProfile, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)301     public static void writeNotificationDismissedEvent(
302             String sourceId,
303             boolean isManagedProfile,
304             String issueTypeId,
305             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
306         writeNotificationInteractionReportedEvent(
307                 SAFETY_CENTER_INTERACTION_REPORTED__ACTION__NOTIFICATION_DISMISSED,
308                 sourceId,
309                 isManagedProfile,
310                 issueTypeId,
311                 sourceSeverityLevel);
312     }
313 
314     /**
315      * Writes a {@link PermissionStatsLog#SAFETY_CENTER_INTERACTION_REPORTED} atom with the action
316      * {@code ISSUE_PRIMARY_ACTION_CLICKED} or {@code ISSUE_SECONDARY_ACTION_CLICKED}.
317      */
writeNotificationActionClickedEvent( String sourceId, boolean isManagedProfile, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel, boolean isPrimaryAction)318     public static void writeNotificationActionClickedEvent(
319             String sourceId,
320             boolean isManagedProfile,
321             String issueTypeId,
322             @SafetySourceData.SeverityLevel int sourceSeverityLevel,
323             boolean isPrimaryAction) {
324         int action =
325                 isPrimaryAction
326                         ? SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_PRIMARY_ACTION_CLICKED
327                         : SAFETY_CENTER_INTERACTION_REPORTED__ACTION__ISSUE_SECONDARY_ACTION_CLICKED;
328         writeNotificationInteractionReportedEvent(
329                 action, sourceId, isManagedProfile, issueTypeId, sourceSeverityLevel);
330     }
331 
writeNotificationInteractionReportedEvent( int interactionReportedAction, String sourceId, boolean isManagedProfile, String issueTypeId, @SafetySourceData.SeverityLevel int sourceSeverityLevel)332     private static void writeNotificationInteractionReportedEvent(
333             int interactionReportedAction,
334             String sourceId,
335             boolean isManagedProfile,
336             String issueTypeId,
337             @SafetySourceData.SeverityLevel int sourceSeverityLevel) {
338         if (!SafetyCenterFlags.getAllowStatsdLogging()) {
339             return;
340         }
341         PermissionStatsLog.write(
342                 SAFETY_CENTER_INTERACTION_REPORTED,
343                 UNSET_SESSION_ID,
344                 interactionReportedAction,
345                 SAFETY_CENTER_INTERACTION_REPORTED__VIEW_TYPE__VIEW_TYPE_NOTIFICATION,
346                 SAFETY_CENTER_INTERACTION_REPORTED__NAVIGATION_SOURCE__SOURCE_UNKNOWN,
347                 toInteractionReportedSeverityLevel(sourceSeverityLevel),
348                 idStringToLong(sourceId),
349                 toInteractionReportedProfileType(isManagedProfile),
350                 idStringToLong(issueTypeId),
351                 SAFETY_CENTER_INTERACTION_REPORTED__SENSOR__SENSOR_UNKNOWN,
352                 UNSET_SOURCE_GROUP_ID,
353                 SAFETY_CENTER_INTERACTION_REPORTED__ISSUE_STATE__ACTIVE);
354     }
355 
356     /**
357      * Returns a {@link SystemEventResult} based on whether the given operation was {@code
358      * successful}.
359      */
360     @SystemEventResult
toSystemEventResult(boolean success)361     public static int toSystemEventResult(boolean success) {
362         return success
363                 ? SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__SUCCESS
364                 : SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__ERROR;
365     }
366 
toSourceRefreshEventType(@efreshRequestType int refreshType)367     private static int toSourceRefreshEventType(@RefreshRequestType int refreshType) {
368         switch (refreshType) {
369             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
370                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_GET_NEW_DATA;
371             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
372                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__SINGLE_SOURCE_RESCAN;
373         }
374         Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
375         return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
376     }
377 
toWholeRefreshEventType(@efreshRequestType int refreshType)378     private static int toWholeRefreshEventType(@RefreshRequestType int refreshType) {
379         switch (refreshType) {
380             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_GET_DATA:
381                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_GET_NEW_DATA;
382             case SafetyCenterManager.EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA:
383                 return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__COMPLETE_RESCAN;
384         }
385         Log.w(TAG, "Unexpected SafetyCenterManager.RefreshRequestType: " + refreshType);
386         return SAFETY_CENTER_SYSTEM_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_UNKNOWN;
387     }
388 
toSourceStateCollectedProfileType(boolean isManagedProfile)389     private static int toSourceStateCollectedProfileType(boolean isManagedProfile) {
390         return isManagedProfile
391                 ? SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
392                 : SAFETY_SOURCE_STATE_COLLECTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
393     }
394 
toSystemEventProfileType(boolean isManagedProfile)395     private static int toSystemEventProfileType(boolean isManagedProfile) {
396         return isManagedProfile
397                 ? SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
398                 : SAFETY_CENTER_SYSTEM_EVENT_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
399     }
400 
toInteractionReportedProfileType(boolean isManagedProfile)401     private static int toInteractionReportedProfileType(boolean isManagedProfile) {
402         return isManagedProfile
403                 ? SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_MANAGED
404                 : SAFETY_CENTER_INTERACTION_REPORTED__SAFETY_SOURCE_PROFILE_TYPE__PROFILE_TYPE_PERSONAL;
405     }
406 
407     /**
408      * Converts a {@link String} ID (e.g. a Safety Source ID) to a {@code long} suitable for logging
409      * to statsd.
410      */
idStringToLong(String id)411     private static long idStringToLong(String id) {
412         MessageDigest messageDigest;
413         try {
414             messageDigest = MessageDigest.getInstance("MD5");
415         } catch (NoSuchAlgorithmException e) {
416             Log.w(TAG, "Couldn't encode safety source id: " + id, e);
417             return 0;
418         }
419         messageDigest.update(id.getBytes());
420         return new BigInteger(messageDigest.digest()).longValue();
421     }
422 
toSafetyStateOverallSeverityLevel( @afetyCenterStatus.OverallSeverityLevel int severityLevel)423     private static int toSafetyStateOverallSeverityLevel(
424             @SafetyCenterStatus.OverallSeverityLevel int severityLevel) {
425         switch (severityLevel) {
426             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN:
427                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
428             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK:
429                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
430             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_RECOMMENDATION:
431                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
432             case SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING:
433                 return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
434         }
435         Log.w(TAG, "Unexpected SafetyCenterStatus.OverallSeverityLevel: " + severityLevel);
436         return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
437     }
438 
toSafetySourceStateCollectedSeverityLevel( @ullable @afetySourceData.SeverityLevel Integer safetySourceSeverityLevel)439     private static int toSafetySourceStateCollectedSeverityLevel(
440             @Nullable @SafetySourceData.SeverityLevel Integer safetySourceSeverityLevel) {
441         if (safetySourceSeverityLevel == null) {
442             return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
443         }
444         switch (safetySourceSeverityLevel) {
445             case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
446                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
447             case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
448                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
449             case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
450                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
451             case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
452                 return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
453         }
454         Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + safetySourceSeverityLevel);
455         return SAFETY_SOURCE_STATE_COLLECTED__SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
456     }
457 
toInteractionReportedSeverityLevel( @afetySourceData.SeverityLevel int severityLevel)458     private static int toInteractionReportedSeverityLevel(
459             @SafetySourceData.SeverityLevel int severityLevel) {
460         switch (severityLevel) {
461             case SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED:
462                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_UNSPECIFIED;
463             case SafetySourceData.SEVERITY_LEVEL_INFORMATION:
464                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_OK;
465             case SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION:
466                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_RECOMMENDATION;
467             case SafetySourceData.SEVERITY_LEVEL_CRITICAL_WARNING:
468                 return SAFETY_CENTER_INTERACTION_REPORTED__SEVERITY_LEVEL__SAFETY_SEVERITY_CRITICAL_WARNING;
469         }
470         Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + severityLevel);
471         return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
472     }
473 
toSafetySourceStateCollectedCollectionType( @ullable SafetyEvent safetyEvent)474     private static int toSafetySourceStateCollectedCollectionType(
475             @Nullable SafetyEvent safetyEvent) {
476         if (safetyEvent == null) {
477             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
478         }
479         if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
480             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
481         } else {
482             return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
483         }
484     }
485 }
486