1 /*
2  * Copyright 2019 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.car.settings.applications;
18 
19 import android.car.drivingstate.CarUxRestrictions;
20 import android.content.Context;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.PermissionGroupInfo;
24 import android.content.pm.PermissionInfo;
25 import android.icu.text.ListFormatter;
26 import android.util.ArraySet;
27 
28 import androidx.preference.Preference;
29 
30 import com.android.car.settings.R;
31 import com.android.car.settings.common.FragmentController;
32 import com.android.car.settings.common.Logger;
33 import com.android.car.settings.common.PreferenceController;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Set;
38 
39 /**
40  * Updates the summary of the entry preference for app permissions to show up to a fixed number of
41  * permission groups currently permitted.
42  */
43 public class AppPermissionsEntryPreferenceController extends PreferenceController<Preference> {
44 
45     private static final Logger LOG = new Logger(AppPermissionsEntryPreferenceController.class);
46 
47     private static final String[] PERMISSION_GROUPS = new String[]{
48             "android.permission-group.LOCATION",
49             "android.permission-group.MICROPHONE",
50             "android.permission-group.CAMERA",
51             "android.permission-group.SMS",
52             "android.permission-group.CONTACTS",
53             "android.permission-group.PHONE"};
54 
55     private static final int NUM_PERMISSION_TO_USE = 3;
56 
57     private PackageManager mPackageManager;
58 
AppPermissionsEntryPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)59     public AppPermissionsEntryPreferenceController(Context context, String preferenceKey,
60             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
61         super(context, preferenceKey, fragmentController, uxRestrictions);
62         mPackageManager = context.getPackageManager();
63     }
64 
65     @Override
getPreferenceType()66     protected Class<Preference> getPreferenceType() {
67         return Preference.class;
68     }
69 
70     @Override
updateState(Preference preference)71     protected void updateState(Preference preference) {
72         Set<String> permissions = getAllPermissionsInGroups();
73         Set<String> grantedPermissionGroups = getGrantedPermissionGroups(permissions);
74         int count = 0;
75         final List<String> summaries = new ArrayList<>();
76 
77         // Iterate over array instead of set to show sensitive permissions first.
78         for (String group : PERMISSION_GROUPS) {
79             if (!grantedPermissionGroups.contains(group)) {
80                 continue;
81             }
82             summaries.add(getPermissionGroupLabel(group).toString().toLowerCase());
83             if (++count >= NUM_PERMISSION_TO_USE) {
84                 break;
85             }
86         }
87         String summary = (count > 0) ? getContext().getString(R.string.app_permissions_summary,
88                 ListFormatter.getInstance().format(summaries)) : null;
89 
90         preference.setSummary(summary);
91     }
92 
getAllPermissionsInGroups()93     private Set<String> getAllPermissionsInGroups() {
94         Set<String> result = new ArraySet<>();
95         for (String group : PERMISSION_GROUPS) {
96             try {
97                 List<PermissionInfo> permissions = mPackageManager.queryPermissionsByGroup(
98                         group, /* flags= */ 0);
99                 for (PermissionInfo permissionInfo : permissions) {
100                     result.add(permissionInfo.name);
101                 }
102             } catch (PackageManager.NameNotFoundException e) {
103                 LOG.e("Error getting permissions in group " + group, e);
104             }
105         }
106         return result;
107     }
108 
getGrantedPermissionGroups(Set<String> permissions)109     private Set<String> getGrantedPermissionGroups(Set<String> permissions) {
110         Set<String> grantedPermissionGroups = new ArraySet<>();
111         List<PackageInfo> installedPackages =
112                 mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
113         for (PackageInfo installedPackage : installedPackages) {
114             if (installedPackage.permissions == null) {
115                 continue;
116             }
117             for (PermissionInfo permissionInfo : installedPackage.permissions) {
118                 if (permissions.contains(permissionInfo.name)) {
119                     grantedPermissionGroups.add(permissionInfo.group);
120                 }
121             }
122         }
123         return grantedPermissionGroups;
124     }
125 
getPermissionGroupLabel(String group)126     private CharSequence getPermissionGroupLabel(String group) {
127         try {
128             PermissionGroupInfo groupInfo = mPackageManager.getPermissionGroupInfo(
129                     group, /* flags= */ 0);
130             return groupInfo.loadLabel(mPackageManager);
131         } catch (PackageManager.NameNotFoundException e) {
132             LOG.e("Error getting permissions label.", e);
133         }
134         return group;
135     }
136 }
137