• 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 com.android.safetycenter.testing
18 
19 import android.app.PendingIntent
20 import android.content.Context
21 import android.icu.text.MessageFormat
22 import android.os.Build.VERSION_CODES.TIRAMISU
23 import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
24 import android.os.Bundle
25 import android.os.UserHandle
26 import android.safetycenter.SafetyCenterData
27 import android.safetycenter.SafetyCenterEntry
28 import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING
29 import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_OK
30 import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_RECOMMENDATION
31 import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNKNOWN
32 import android.safetycenter.SafetyCenterEntry.ENTRY_SEVERITY_LEVEL_UNSPECIFIED
33 import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON
34 import android.safetycenter.SafetyCenterEntry.SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION
35 import android.safetycenter.SafetyCenterIssue
36 import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING
37 import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
38 import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATION
39 import android.safetycenter.SafetyCenterStatus
40 import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING
41 import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_OK
42 import android.safetycenter.SafetyCenterStatus.OVERALL_SEVERITY_LEVEL_UNKNOWN
43 import android.util.ArrayMap
44 import androidx.annotation.RequiresApi
45 import com.android.modules.utils.build.SdkLevel
46 import com.android.safetycenter.internaldata.SafetyCenterEntryId
47 import com.android.safetycenter.internaldata.SafetyCenterIds
48 import com.android.safetycenter.internaldata.SafetyCenterIssueActionId
49 import com.android.safetycenter.internaldata.SafetyCenterIssueId
50 import com.android.safetycenter.internaldata.SafetyCenterIssueKey
51 import com.android.safetycenter.resources.SafetyCenterResourcesContext
52 import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SINGLE_SOURCE_GROUP_ID
53 import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ACTION_ID
54 import com.android.safetycenter.testing.SafetySourceTestData.Companion.CRITICAL_ISSUE_ID
55 import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ACTION_ID
56 import com.android.safetycenter.testing.SafetySourceTestData.Companion.INFORMATION_ISSUE_ID
57 import com.android.safetycenter.testing.SafetySourceTestData.Companion.ISSUE_TYPE_ID
58 import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ACTION_ID
59 import com.android.safetycenter.testing.SafetySourceTestData.Companion.RECOMMENDATION_ISSUE_ID
60 import java.util.Locale
61 
62 /**
63  * A class that provides [SafetyCenterData] objects and associated constants to facilitate asserting
64  * on specific Safety Center states in SafetyCenter for testing.
65  */
66 @RequiresApi(TIRAMISU)
67 class SafetyCenterTestData(context: Context) {
68 
69     private val safetyCenterResourcesContext = SafetyCenterResourcesContext.forTests(context)
70     private val safetySourceTestData = SafetySourceTestData(context)
71 
72     /**
73      * The [SafetyCenterStatus] used when the overall status is unknown and no scan is in progress.
74      */
75     val safetyCenterStatusUnknown =
76         SafetyCenterStatus.Builder(
77                 safetyCenterResourcesContext.getStringByName(
78                     "overall_severity_level_ok_review_title"
79                 ),
80                 safetyCenterResourcesContext.getStringByName(
81                     "overall_severity_level_ok_review_summary"
82                 )
83             )
84             .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
85             .build()
86 
87     /**
88      * Returns a [SafetyCenterStatus] with one alert and the given [statusResource] and
89      * [overallSeverityLevel].
90      */
safetyCenterStatusOneAlertnull91     fun safetyCenterStatusOneAlert(
92         statusResource: String,
93         overallSeverityLevel: Int
94     ): SafetyCenterStatus = safetyCenterStatusNAlerts(statusResource, overallSeverityLevel, 1)
95 
96     /**
97      * Returns a [SafetyCenterStatus] with [numAlerts] and the given [statusResource] and
98      * [overallSeverityLevel].
99      */
100     fun safetyCenterStatusNAlerts(
101         statusResource: String,
102         overallSeverityLevel: Int,
103         numAlerts: Int,
104     ): SafetyCenterStatus =
105         SafetyCenterStatus.Builder(
106                 safetyCenterResourcesContext.getStringByName(statusResource),
107                 getAlertString(numAlerts)
108             )
109             .setSeverityLevel(overallSeverityLevel)
110             .build()
111 
112     /**
113      * Returns an information [SafetyCenterStatus] that has "Tip(s) available" as a summary for the
114      * given [numTipIssues].
115      */
116     fun safetyCenterStatusTips(
117         numTipIssues: Int,
118     ): SafetyCenterStatus =
119         SafetyCenterStatus.Builder(
120                 safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
121                 safetyCenterResourcesContext.getStringByName(
122                     "overall_severity_level_tip_summary",
123                     numTipIssues
124                 )
125             )
126             .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
127             .build()
128 
129     /**
130      * Returns an information [SafetyCenterStatus] that has "Action(s) taken" as a summary for the
131      * given [numAutomaticIssues].
132      */
133     fun safetyCenterStatusActionsTaken(
134         numAutomaticIssues: Int,
135     ): SafetyCenterStatus =
136         SafetyCenterStatus.Builder(
137                 safetyCenterResourcesContext.getStringByName("overall_severity_level_ok_title"),
138                 safetyCenterResourcesContext.getStringByName(
139                     "overall_severity_level_action_taken_summary",
140                     numAutomaticIssues
141                 )
142             )
143             .setSeverityLevel(OVERALL_SEVERITY_LEVEL_OK)
144             .build()
145 
146     /**
147      * Returns the [SafetyCenterStatus] used when the overall status is critical and no scan is in
148      * progress for the given number of alerts.
149      */
150     fun safetyCenterStatusCritical(numAlerts: Int) =
151         SafetyCenterStatus.Builder(
152                 safetyCenterResourcesContext.getStringByName(
153                     "overall_severity_level_critical_safety_warning_title"
154                 ),
155                 getAlertString(numAlerts)
156             )
157             .setSeverityLevel(OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING)
158             .build()
159 
160     /**
161      * Returns a [SafetyCenterEntry] builder with a grey icon (for unknown severity), the summary
162      * generally used for sources of the [SafetyCenterTestConfigs], and a pending intent that
163      * redirects to [TestActivity] for the given source, user id, and title.
164      */
165     fun safetyCenterEntryDefaultBuilder(
166         sourceId: String,
167         userId: Int = UserHandle.myUserId(),
168         title: CharSequence = "OK",
169         pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
170     ) =
171         SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
172             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNKNOWN)
173             .setSummary("OK")
174             .setPendingIntent(pendingIntent)
175             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
176 
177     /**
178      * Returns a [SafetyCenterEntry] with a grey icon (for unknown severity), the summary generally
179      * used for sources of the [SafetyCenterTestConfigs], and a pending intent that redirects to
180      * Safety Center for the given source, user id, and title.
181      */
182     fun safetyCenterEntryDefault(
183         sourceId: String,
184         userId: Int = UserHandle.myUserId(),
185         title: CharSequence = "OK",
186         pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
187     ) = safetyCenterEntryDefaultBuilder(sourceId, userId, title, pendingIntent).build()
188 
189     /**
190      * Returns a [SafetyCenterEntry] builder with no icon, the summary generally used for sources of
191      * the [SafetyCenterTestConfigs], and a pending intent that redirects to [TestActivity] for the
192      * given source, user id, and title.
193      */
194     fun safetyCenterEntryDefaultStaticBuilder(
195         sourceId: String,
196         userId: Int = UserHandle.myUserId(),
197         title: CharSequence = "OK"
198     ) =
199         SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
200             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
201             .setSummary("OK")
202             .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
203             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_ICON)
204 
205     /**
206      * Returns a [SafetyCenterEntry] with a grey icon (for unknown severity), a refresh error
207      * summary, and a pending intent that redirects to [TestActivity] for the given source, user id,
208      * and title.
209      */
210     fun safetyCenterEntryError(sourceId: String) =
211         safetyCenterEntryDefaultBuilder(sourceId).setSummary(getRefreshErrorString(1)).build()
212 
213     /**
214      * Returns a disabled [SafetyCenterEntry] with a grey icon (for unspecified severity), a
215      * standard summary, and a standard title for the given source and pending intent.
216      */
217     fun safetyCenterEntryUnspecified(
218         sourceId: String,
219         pendingIntent: PendingIntent? = safetySourceTestData.testActivityRedirectPendingIntent
220     ) =
221         SafetyCenterEntry.Builder(entryId(sourceId), "Unspecified title")
222             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_UNSPECIFIED)
223             .setSummary("Unspecified summary")
224             .setPendingIntent(pendingIntent)
225             .setEnabled(false)
226             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
227             .build()
228 
229     /**
230      * Returns a [SafetyCenterEntry] builder with a green icon (for ok severity), a standard
231      * summary, and a pending intent that redirects to [TestActivity] for the given source, user id,
232      * and title.
233      */
234     fun safetyCenterEntryOkBuilder(
235         sourceId: String,
236         userId: Int = UserHandle.myUserId(),
237         title: CharSequence = "Ok title"
238     ) =
239         SafetyCenterEntry.Builder(entryId(sourceId, userId), title)
240             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_OK)
241             .setSummary("Ok summary")
242             .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
243             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
244 
245     /**
246      * Returns a [SafetyCenterEntry] with a green icon (for ok severity), a standard summary, and a
247      * pending intent that redirects to [TestActivity] for the given source, user id, and title.
248      */
249     fun safetyCenterEntryOk(
250         sourceId: String,
251         userId: Int = UserHandle.myUserId(),
252         title: CharSequence = "Ok title"
253     ) = safetyCenterEntryOkBuilder(sourceId, userId, title).build()
254 
255     /**
256      * Returns a [SafetyCenterEntry] with a yellow icon (for recommendation severity), a standard
257      * title, and a pending intent that redirects to [TestActivity] for the given source and
258      * summary.
259      */
260     fun safetyCenterEntryRecommendation(
261         sourceId: String,
262         summary: String = "Recommendation summary"
263     ) =
264         SafetyCenterEntry.Builder(entryId(sourceId), "Recommendation title")
265             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_RECOMMENDATION)
266             .setSummary(summary)
267             .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
268             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
269             .build()
270 
271     /**
272      * Returns a [SafetyCenterEntry] with a red icon (for critical severity), a standard title, a
273      * standard summary, and a pending intent that redirects to [TestActivity] for the given source.
274      */
275     fun safetyCenterEntryCritical(sourceId: String) =
276         SafetyCenterEntry.Builder(entryId(sourceId), "Critical title")
277             .setSeverityLevel(ENTRY_SEVERITY_LEVEL_CRITICAL_WARNING)
278             .setSummary("Critical summary")
279             .setPendingIntent(safetySourceTestData.testActivityRedirectPendingIntent)
280             .setSeverityUnspecifiedIconType(SEVERITY_UNSPECIFIED_ICON_TYPE_NO_RECOMMENDATION)
281             .build()
282 
283     /**
284      * Returns an information [SafetyCenterIssue] for the given source and user id that is
285      * consistent with information [SafetySourceIssue]s used in [SafetySourceTestData].
286      */
287     fun safetyCenterIssueInformation(
288         sourceId: String,
289         userId: Int = UserHandle.myUserId(),
290         attributionTitle: String? = "OK",
291         groupId: String? = SINGLE_SOURCE_GROUP_ID
292     ) =
293         SafetyCenterIssue.Builder(
294                 issueId(sourceId, INFORMATION_ISSUE_ID, userId = userId),
295                 "Information issue title",
296                 "Information issue summary"
297             )
298             .setSeverityLevel(ISSUE_SEVERITY_LEVEL_OK)
299             .setShouldConfirmDismissal(false)
300             .setActions(
301                 listOf(
302                     SafetyCenterIssue.Action.Builder(
303                             issueActionId(
304                                 sourceId,
305                                 INFORMATION_ISSUE_ID,
306                                 INFORMATION_ISSUE_ACTION_ID,
307                                 userId
308                             ),
309                             "Review",
310                             safetySourceTestData.testActivityRedirectPendingIntent
311                         )
312                         .build()
313                 )
314             )
315             .apply {
316                 if (SdkLevel.isAtLeastU()) {
317                     setAttributionTitle(attributionTitle)
318                     setGroupId(groupId)
319                 }
320             }
321             .build()
322 
323     /**
324      * Returns a recommendation [SafetyCenterIssue] for the given source and user id that is
325      * consistent with recommendation [SafetySourceIssue]s used in [SafetySourceTestData].
326      */
safetyCenterIssueRecommendationnull327     fun safetyCenterIssueRecommendation(
328         sourceId: String,
329         userId: Int = UserHandle.myUserId(),
330         attributionTitle: String? = "OK",
331         groupId: String? = SINGLE_SOURCE_GROUP_ID,
332         confirmationDialog: Boolean = false
333     ) =
334         SafetyCenterIssue.Builder(
335                 issueId(sourceId, RECOMMENDATION_ISSUE_ID, userId = userId),
336                 "Recommendation issue title",
337                 "Recommendation issue summary"
338             )
339             .setSeverityLevel(ISSUE_SEVERITY_LEVEL_RECOMMENDATION)
340             .setActions(
341                 listOf(
342                     SafetyCenterIssue.Action.Builder(
343                             issueActionId(
344                                 sourceId,
345                                 RECOMMENDATION_ISSUE_ID,
346                                 RECOMMENDATION_ISSUE_ACTION_ID,
347                                 userId
348                             ),
349                             "See issue",
350                             safetySourceTestData.testActivityRedirectPendingIntent
351                         )
352                         .apply {
353                             if (confirmationDialog && SdkLevel.isAtLeastU()) {
354                                 setConfirmationDialogDetails(
355                                     SafetyCenterIssue.Action.ConfirmationDialogDetails(
356                                         "Confirmation title",
357                                         "Confirmation text",
358                                         "Confirmation yes",
359                                         "Confirmation no"
360                                     )
361                                 )
362                             }
363                         }
364                         .build()
365                 )
366             )
<lambda>null367             .apply {
368                 if (SdkLevel.isAtLeastU()) {
369                     setAttributionTitle(attributionTitle)
370                     setGroupId(groupId)
371                 }
372             }
373             .build()
374 
375     /**
376      * Returns a critical [SafetyCenterIssue] for the given source and user id that is consistent
377      * with critical [SafetySourceIssue]s used in [SafetySourceTestData].
378      */
safetyCenterIssueCriticalnull379     fun safetyCenterIssueCritical(
380         sourceId: String,
381         isActionInFlight: Boolean = false,
382         userId: Int = UserHandle.myUserId(),
383         attributionTitle: String? = "OK",
384         groupId: String? = SINGLE_SOURCE_GROUP_ID
385     ) =
386         SafetyCenterIssue.Builder(
387                 issueId(sourceId, CRITICAL_ISSUE_ID, userId = userId),
388                 "Critical issue title",
389                 "Critical issue summary"
390             )
391             .setSeverityLevel(ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING)
392             .setActions(
393                 listOf(
394                     SafetyCenterIssue.Action.Builder(
395                             issueActionId(
396                                 sourceId,
397                                 CRITICAL_ISSUE_ID,
398                                 CRITICAL_ISSUE_ACTION_ID,
399                                 userId
400                             ),
401                             "Solve issue",
402                             safetySourceTestData.criticalIssueActionPendingIntent
403                         )
404                         .setWillResolve(true)
405                         .setIsInFlight(isActionInFlight)
406                         .build()
407                 )
408             )
409             .apply {
410                 if (SdkLevel.isAtLeastU()) {
411                     setAttributionTitle(attributionTitle)
412                     setGroupId(groupId)
413                 }
414             }
415             .build()
416 
417     /**
418      * Returns the [overall_severity_n_alerts_summary] string formatted for the given number of
419      * alerts.
420      */
getAlertStringnull421     fun getAlertString(numberOfAlerts: Int): String =
422         getIcuPluralsString("overall_severity_n_alerts_summary", numberOfAlerts)
423 
424     /** Returns the [refresh_error] string formatted for the given number of error entries. */
425     fun getRefreshErrorString(numberOfErrorEntries: Int): String =
426         getIcuPluralsString("refresh_error", numberOfErrorEntries)
427 
428     private fun getIcuPluralsString(name: String, count: Int, vararg formatArgs: Any): String {
429         val messageFormat =
430             MessageFormat(
431                 safetyCenterResourcesContext.getStringByName(name, formatArgs),
432                 Locale.getDefault()
433             )
434         val arguments = ArrayMap<String, Any>()
435         arguments["count"] = count
436         return messageFormat.format(arguments)
437     }
438 
439     companion object {
440         /** The default [SafetyCenterData] returned by the Safety Center APIs. */
441         val DEFAULT: SafetyCenterData =
442             SafetyCenterData(
443                 SafetyCenterStatus.Builder("", "")
444                     .setSeverityLevel(OVERALL_SEVERITY_LEVEL_UNKNOWN)
445                     .build(),
446                 emptyList(),
447                 emptyList(),
448                 emptyList()
449             )
450 
451         /** Creates an ID for a Safety Center entry. */
entryIdnull452         fun entryId(sourceId: String, userId: Int = UserHandle.myUserId()) =
453             SafetyCenterIds.encodeToString(
454                 SafetyCenterEntryId.newBuilder()
455                     .setSafetySourceId(sourceId)
456                     .setUserId(userId)
457                     .build()
458             )
459 
460         /** Creates an ID for a Safety Center issue. */
461         fun issueId(
462             sourceId: String,
463             sourceIssueId: String,
464             issueTypeId: String = ISSUE_TYPE_ID,
465             userId: Int = UserHandle.myUserId()
466         ) =
467             SafetyCenterIds.encodeToString(
468                 SafetyCenterIssueId.newBuilder()
469                     .setSafetyCenterIssueKey(
470                         SafetyCenterIssueKey.newBuilder()
471                             .setSafetySourceId(sourceId)
472                             .setSafetySourceIssueId(sourceIssueId)
473                             .setUserId(userId)
474                             .build()
475                     )
476                     .setIssueTypeId(issueTypeId)
477                     .build()
478             )
479 
480         /** Creates an ID for a Safety Center issue action. */
481         fun issueActionId(
482             sourceId: String,
483             sourceIssueId: String,
484             sourceIssueActionId: String,
485             userId: Int = UserHandle.myUserId()
486         ) =
487             SafetyCenterIds.encodeToString(
488                 SafetyCenterIssueActionId.newBuilder()
489                     .setSafetyCenterIssueKey(
490                         SafetyCenterIssueKey.newBuilder()
491                             .setSafetySourceId(sourceId)
492                             .setSafetySourceIssueId(sourceIssueId)
493                             .setUserId(userId)
494                             .build()
495                     )
496                     .setSafetySourceIssueActionId(sourceIssueActionId)
497                     .build()
498             )
499 
500         /**
501          * On U+, returns a new [SafetyCenterData] with the dismissed issues set. Prior to U,
502          * returns the passed in [SafetyCenterData].
503          */
504         fun SafetyCenterData.withDismissedIssuesIfAtLeastU(
505             dismissedIssues: List<SafetyCenterIssue>
506         ): SafetyCenterData =
507             if (SdkLevel.isAtLeastU()) {
508                 copy(dismissedIssues = dismissedIssues)
509             } else this
510 
511         /** Returns a [SafetyCenterData] without extras. */
SafetyCenterDatanull512         fun SafetyCenterData.withoutExtras() =
513             if (SdkLevel.isAtLeastU()) {
514                 SafetyCenterData.Builder(this).clearExtras().build()
515             } else this
516 
517         /**
518          * On U+, returns a new [SafetyCenterData] with [SafetyCenterIssue]s having the
519          * [attributionTitle]. Prior to U, returns the passed in [SafetyCenterData].
520          */
SafetyCenterDatanull521         fun SafetyCenterData.withAttributionTitleInIssuesIfAtLeastU(
522             attributionTitle: String?
523         ): SafetyCenterData {
524             return if (SdkLevel.isAtLeastU()) {
525                 val issuesWithAttributionTitle =
526                     this.issues.map {
527                         SafetyCenterIssue.Builder(it).setAttributionTitle(attributionTitle).build()
528                     }
529                 copy(issues = issuesWithAttributionTitle)
530             } else this
531         }
532 
533         /**
534          * On U+, returns a new [SafetyCenterData] with the extras set. Prior to U, returns the
535          * passed in [SafetyCenterData].
536          */
SafetyCenterDatanull537         fun SafetyCenterData.withExtrasIfAtLeastU(extras: Bundle): SafetyCenterData =
538             if (SdkLevel.isAtLeastU()) {
539                 copy(extras = extras)
540             } else this
541 
542         @RequiresApi(UPSIDE_DOWN_CAKE)
SafetyCenterDatanull543         private fun SafetyCenterData.copy(
544             issues: List<SafetyCenterIssue> = this.issues,
545             dismissedIssues: List<SafetyCenterIssue> = this.dismissedIssues,
546             extras: Bundle = this.extras
547         ): SafetyCenterData =
548             SafetyCenterData.Builder(status)
549                 .apply {
550                     issues.forEach(::addIssue)
551                     entriesOrGroups.forEach(::addEntryOrGroup)
552                     staticEntryGroups.forEach(::addStaticEntryGroup)
553                     dismissedIssues.forEach(::addDismissedIssue)
554                 }
555                 .setExtras(extras)
556                 .build()
557     }
558 }
559