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.permissioncontroller.permission.model.v34
18 
19 import android.os.Build
20 import androidx.annotation.RequiresApi
21 import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
22 import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_ADVERTISING_PURPOSE
23 import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
24 import com.android.permissioncontroller.permission.model.v34.DataSharingUpdateType.ADDS_SHARING_WITH_ADVERTISING_PURPOSE
25 import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.AppSafetyLabelDiff
26 import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory.SafetyLabel
27 
28 /**
29  * Class representing a significant update in an app's data sharing policy from its safety label.
30  *
31  * Note that safety labels are part of package information, and therefore the safety label
32  * information applies to apps for all users that have the app installed.
33  */
34 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
35 data class AppDataSharingUpdate(
36     /** Package name for the app with the data sharing update. */
37     val packageName: String,
38     /** How data sharing for each category has changed. */
39     val categorySharingUpdates: Map<String, DataSharingUpdateType>
40 ) {
41 
42     /** Companion object for [AppDataSharingUpdate]. */
43     companion object {
44         /**
45          * Builds and returns an [AppDataSharingUpdate] from an [AppSafetyLabelDiff], if the change
46          * in safety labels is significant, else returns null.
47          */
buildUpdateIfSignificantChangenull48         fun AppSafetyLabelDiff.buildUpdateIfSignificantChange(): AppDataSharingUpdate? {
49             // In Android U, only updates for the location data category will be displayed in
50             // the UI.
51             val updates = getUpdatesForCategories(listOf(CATEGORY_LOCATION))
52 
53             return if (updates.isEmpty()) null
54             else AppDataSharingUpdate(safetyLabelBefore.appInfo.packageName, updates)
55         }
56 
AppSafetyLabelDiffnull57         private fun AppSafetyLabelDiff.getUpdatesForCategories(
58             categories: List<String>
59         ): Map<String, DataSharingUpdateType> {
60             val categoryUpdateMap = mutableMapOf<String, DataSharingUpdateType>()
61 
62             for (category in categories) {
63                 var categoryUpdateType: DataSharingUpdateType?
64 
65                 val beforeSharesData = safetyLabelBefore.sharesData(category)
66                 val beforeSharesDataForAds = safetyLabelBefore.sharesDataForAdsPurpose(category)
67                 val afterSharesData = safetyLabelAfter.sharesData(category)
68                 val afterSharesDataForAds = safetyLabelAfter.sharesDataForAdsPurpose(category)
69 
70                 categoryUpdateType =
71                     when {
72                         !beforeSharesData && afterSharesDataForAds ->
73                             ADDS_SHARING_WITH_ADVERTISING_PURPOSE
74                         !beforeSharesData && afterSharesData && !afterSharesDataForAds ->
75                             ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE
76                         beforeSharesData && !beforeSharesDataForAds && afterSharesDataForAds ->
77                             ADDS_ADVERTISING_PURPOSE
78                         else -> null
79                     }
80 
81                 if (categoryUpdateType == null) {
82                     continue
83                 }
84 
85                 categoryUpdateMap[category] = categoryUpdateType
86             }
87 
88             return categoryUpdateMap
89         }
90 
SafetyLabelnull91         private fun SafetyLabel.sharesData(category: String) =
92             dataLabel.dataShared.containsKey(category)
93 
94         private fun SafetyLabel.sharesDataForAdsPurpose(category: String) =
95             dataLabel.dataShared[category]?.containsAdvertisingPurpose ?: false
96     }
97 }
98 
99 /**
100  * Different ways in which data sharing can be significantly updated for a particular data category.
101  */
102 enum class DataSharingUpdateType {
103     ADDS_ADVERTISING_PURPOSE,
104     ADDS_SHARING_WITHOUT_ADVERTISING_PURPOSE,
105     ADDS_SHARING_WITH_ADVERTISING_PURPOSE
106 }
107