• 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.permissioncontroller.safetycenter.ui.model
18 
19 import android.os.Build.VERSION_CODES.TIRAMISU
20 import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
21 import android.safetycenter.SafetyCenterData
22 import android.safetycenter.SafetyCenterEntryGroup
23 import android.safetycenter.SafetyCenterEntryOrGroup
24 import android.safetycenter.SafetyCenterIssue
25 import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_OK
26 import androidx.annotation.RequiresApi
27 import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY
28 import com.android.safetycenter.internaldata.SafetyCenterIds
29 import com.android.safetycenter.internaldata.SafetyCenterIssueKey
30 
31 /** UI model representation of Safety Center Data */
32 @RequiresApi(TIRAMISU)
33 data class SafetyCenterUiData(
34     val safetyCenterData: SafetyCenterData,
35     private val taskId: Int,
36     private val sameTaskSourceIds: List<String>,
37     val resolvedIssues: Map<IssueId, ActionId> = emptyMap(),
38 ) {
39 
40     val issueUiDatas: List<IssueUiData> by
<lambda>null41         lazy(LazyThreadSafetyMode.NONE) {
42             safetyCenterData.issues.map { toIssueUiData(it, isDismissed = false) }
43         }
44 
getMatchingIssuenull45     fun getMatchingIssue(issueKey: SafetyCenterIssueKey): SafetyCenterIssue? {
46         return safetyCenterData.issues.find {
47             SafetyCenterIds.issueIdFromString(it.id).safetyCenterIssueKey == issueKey
48         }
49     }
50 
51     /** Returns the [SafetyCenterEntryGroup] corresponding to the provided ID */
52     @RequiresApi(UPSIDE_DOWN_CAKE)
getMatchingGroupnull53     fun getMatchingGroup(groupId: String): SafetyCenterEntryGroup? {
54         val entryOrGroups: List<SafetyCenterEntryOrGroup> = safetyCenterData.entriesOrGroups
55         val entryGroups = entryOrGroups.mapNotNull { it.entryGroup }
56         return entryGroups.find { it.id == groupId }
57     }
58 
59     /**
60      * Returns a list of [SafetyCenterIssue] corresponding to the provided ID. This will be
61      * displayed as warning cards on a subpage in Safety Center.
62      */
63     @RequiresApi(UPSIDE_DOWN_CAKE)
getMatchingIssuesnull64     fun getMatchingIssues(groupId: String): List<SafetyCenterIssue> =
65         selectMatchingIssuesForGroup(groupId, safetyCenterData.issues)
66 
67     /**
68      * Returns a list of dismissed [SafetyCenterIssue] corresponding to the provided ID. This will
69      * be displayed as dismissed warning cards on a subpage in Safety Center.
70      */
71     @RequiresApi(UPSIDE_DOWN_CAKE)
72     fun getMatchingDismissedIssues(groupId: String): List<SafetyCenterIssue> =
73         selectMatchingIssuesForGroup(groupId, safetyCenterData.visibleDismissedIssues())
74 
75     @RequiresApi(UPSIDE_DOWN_CAKE)
76     private fun selectMatchingIssuesForGroup(
77         groupId: String,
78         issues: List<SafetyCenterIssue>,
79     ): List<SafetyCenterIssue> {
80         val issuesToGroups = safetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY)
81         return issues.filter {
82             val mappingExists = issuesToGroups?.containsKey(it.id) ?: false
83             val matchesInMapping =
84                 issuesToGroups?.getStringArrayList(it.id)?.contains(groupId) ?: false
85             val matchesByDefault = it.groupId == groupId
86 
87             if (mappingExists) matchesInMapping else matchesByDefault
88         }
89     }
90 
91     /** Returns the [SafetyCenterData.getDismissedIssues] that are meant to be visible in the UI. */
92     @RequiresApi(UPSIDE_DOWN_CAKE)
SafetyCenterDatanull93     private fun SafetyCenterData.visibleDismissedIssues() =
94         dismissedIssues.filter { it.severityLevel > ISSUE_SEVERITY_LEVEL_OK }
95 
96     /** Converts a [SafetyCenterIssue] into [IssueUiData]. */
toIssueUiDatanull97     private fun toIssueUiData(issue: SafetyCenterIssue, isDismissed: Boolean) =
98         IssueUiData(issue, isDismissed, resolvedIssues[issue.id], getLaunchTaskIdForIssue(issue))
99 
100     private fun getLaunchTaskIdForIssue(issue: SafetyCenterIssue): Int? {
101         val sourceId: String =
102             SafetyCenterIds.issueIdFromString(issue.id)
103                 .getSafetyCenterIssueKey()
104                 .getSafetySourceId()
105         return if (sameTaskSourceIds.contains(sourceId)) taskId else null
106     }
107 }
108