• 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.systemui.car.privacy;
18 
19 import static android.os.UserHandle.USER_SYSTEM;
20 
21 import android.Manifest;
22 import android.content.Context;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.UserInfo;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 import android.permission.PermissionGroupUsage;
29 import android.permission.PermissionManager;
30 import android.util.Log;
31 
32 import androidx.annotation.Nullable;
33 import androidx.annotation.WorkerThread;
34 
35 import com.android.systemui.privacy.PrivacyDialog;
36 import com.android.systemui.privacy.PrivacyItemController;
37 import com.android.systemui.privacy.PrivacyType;
38 import com.android.systemui.privacy.logging.PrivacyLogger;
39 import com.android.systemui.settings.UserTracker;
40 
41 import java.util.ArrayList;
42 import java.util.Comparator;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Optional;
46 import java.util.stream.Collectors;
47 
48 /**
49  * Implementation of {@link
50  * com.android.systemui.car.privacy.SensorQcPanel.SensorPrivacyElementsProvider}
51  */
52 public abstract class PrivacyElementsProviderImpl implements
53         SensorQcPanel.SensorPrivacyElementsProvider {
54     private static final String TAG = "PrivacyElementsProviderImpl";
55     private static final String EMPTY_APP_NAME = "";
56 
57     private static final Map<String, PrivacyType> PERM_GROUP_TO_PRIVACY_TYPE_MAP =
58             Map.of(Manifest.permission_group.CAMERA, PrivacyType.TYPE_CAMERA,
59                     Manifest.permission_group.MICROPHONE, PrivacyType.TYPE_MICROPHONE,
60                     Manifest.permission_group.LOCATION, PrivacyType.TYPE_LOCATION);
61 
62 
63     private final PermissionManager mPermissionManager;
64     private final UserTracker mUserTracker;
65     private final PrivacyLogger mPrivacyLogger;
66     private final PackageManager mPackageManager;
67     private final PrivacyItemController mPrivacyItemController;
68     private final UserManager mUserManager;
69 
PrivacyElementsProviderImpl( Context context, PermissionManager permissionManager, PackageManager packageManager, PrivacyItemController privacyItemController, UserTracker userTracker, PrivacyLogger privacyLogger)70     public PrivacyElementsProviderImpl(
71             Context context,
72             PermissionManager permissionManager,
73             PackageManager packageManager,
74             PrivacyItemController privacyItemController,
75             UserTracker userTracker,
76             PrivacyLogger privacyLogger) {
77         mPermissionManager = permissionManager;
78         mPackageManager = packageManager;
79         mPrivacyItemController = privacyItemController;
80         mUserTracker = userTracker;
81         mPrivacyLogger = privacyLogger;
82 
83         mUserManager = context.getSystemService(UserManager.class);
84     }
85 
86     @Override
getPrivacyElements()87     public List<PrivacyDialog.PrivacyElement> getPrivacyElements() {
88         List<PrivacyDialog.PrivacyElement> elements = filterAndSort(createPrivacyElements());
89         mPrivacyLogger.logShowDialogContents(elements);
90         return elements;
91     }
92 
getProviderPrivacyType()93     protected abstract PrivacyType getProviderPrivacyType();
94 
createPrivacyElements()95     private List<PrivacyDialog.PrivacyElement> createPrivacyElements() {
96         List<UserInfo> userInfos = mUserTracker.getUserProfiles();
97         List<PermissionGroupUsage> permGroupUsages = getPermGroupUsages();
98         mPrivacyLogger.logUnfilteredPermGroupUsage(permGroupUsages);
99         List<PrivacyDialog.PrivacyElement> items = new ArrayList<>();
100 
101         permGroupUsages.forEach(usage -> {
102             PrivacyType type =
103                     verifyType(PERM_GROUP_TO_PRIVACY_TYPE_MAP.get(usage.getPermissionGroupName()));
104             if (type == null) return;
105 
106             int userId = UserHandle.getUserId(usage.getUid());
107             Optional<UserInfo> optionalUserInfo = userInfos.stream()
108                     .filter(ui -> ui.id == userId)
109                     .findFirst();
110             if (!optionalUserInfo.isPresent() && userId != USER_SYSTEM) return;
111 
112             UserInfo userInfo =
113                     optionalUserInfo.orElseGet(() -> mUserManager.getUserInfo(USER_SYSTEM));
114 
115             String appName = usage.isPhoneCall()
116                     ? EMPTY_APP_NAME
117                     : getLabelForPackage(usage.getPackageName(), usage.getUid());
118 
119             items.add(
120                     new PrivacyDialog.PrivacyElement(
121                             type,
122                             usage.getPackageName(),
123                             userId,
124                             appName,
125                             usage.getAttributionTag(),
126                             /* attributionLabel= */ null,
127                             usage.getProxyLabel(),
128                             usage.getLastAccessTimeMillis(),
129                             usage.isActive(),
130                             userInfo.isManagedProfile(),
131                             usage.isPhoneCall(),
132                             usage.getPermissionGroupName(),
133                             /* navigationIntent= */ null)
134             );
135         });
136 
137         return items;
138     }
139 
getApplicationInfo(String packageName, int userId)140     private Optional<ApplicationInfo> getApplicationInfo(String packageName, int userId) {
141         ApplicationInfo applicationInfo;
142         try {
143             applicationInfo = mPackageManager
144                     .getApplicationInfoAsUser(packageName, /* flags= */ 0, userId);
145             return Optional.of(applicationInfo);
146         } catch (PackageManager.NameNotFoundException e) {
147             Log.w(TAG, "Application info not found for: " + packageName);
148             return Optional.empty();
149         }
150     }
151 
152     @WorkerThread
getPermGroupUsages()153     private List<PermissionGroupUsage> getPermGroupUsages() {
154         return mPermissionManager.getIndicatorAppOpUsageData();
155     }
156 
157     @WorkerThread
getLabelForPackage(String packageName, int userId)158     private String getLabelForPackage(String packageName, int userId) {
159         Optional<ApplicationInfo> applicationInfo = getApplicationInfo(packageName, userId);
160 
161         if (!applicationInfo.isPresent()) return packageName;
162 
163         return (String) applicationInfo.get().loadLabel(mPackageManager);
164     }
165 
166     /**
167      * If {@link PrivacyType} is available then returns the argument, or else returns {@code null}.
168      */
169     @Nullable
verifyType(PrivacyType type)170     private PrivacyType verifyType(PrivacyType type) {
171         if ((type == PrivacyType.TYPE_CAMERA || type == PrivacyType.TYPE_MICROPHONE)
172                 && mPrivacyItemController.getMicCameraAvailable()) {
173             return type;
174         } else if (type == PrivacyType.TYPE_LOCATION
175                 && mPrivacyItemController.getLocationAvailable()) {
176             return type;
177         } else {
178             return null;
179         }
180     }
181 
filterAndSort( List<PrivacyDialog.PrivacyElement> list)182     private List<PrivacyDialog.PrivacyElement> filterAndSort(
183             List<PrivacyDialog.PrivacyElement> list) {
184         return list.stream()
185                 .filter(it -> it.getType() == getProviderPrivacyType())
186                 .sorted(new PrivacyElementComparator())
187                 .collect(Collectors.toList());
188     }
189 
190     private static class PrivacyElementComparator
191             implements Comparator<PrivacyDialog.PrivacyElement> {
192         @Override
compare(PrivacyDialog.PrivacyElement it1, PrivacyDialog.PrivacyElement it2)193         public int compare(PrivacyDialog.PrivacyElement it1, PrivacyDialog.PrivacyElement it2) {
194             if (it1.getActive() && !it2.getActive()) {
195                 return 1;
196             } else if (!it1.getActive() && it2.getActive()) {
197                 return -1;
198             } else {
199                 return Long.compare(it1.getLastActiveTimestamp(), it2.getLastActiveTimestamp());
200             }
201         }
202     }
203 }
204