From 0789b5d2269d80fb941a2154e32d926555cbbdc9 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Wed, 24 Apr 2019 21:15:11 +0800 Subject: [PATCH] Use PermissionControllerManager to get permission groups The mapping of permissions and permission groups may be changed upon mainline module update, so we cannot reliably read from the platform. PermissionControllerManager is created for this purpose, so we use it to prevent from the outdated mapping instead of mapping them manually. Bug: 117978938 Test: robotests Change-Id: If8682796b8a30dee3b73572e977fade48d07eb2b --- .../AppPermissionsPreferenceController.java | 124 +++++------- ...ppPermissionsPreferenceControllerTest.java | 176 ++++-------------- 2 files changed, 86 insertions(+), 214 deletions(-) diff --git a/src/com/android/settings/applications/AppPermissionsPreferenceController.java b/src/com/android/settings/applications/AppPermissionsPreferenceController.java index 0137276c942..751e33854d4 100644 --- a/src/com/android/settings/applications/AppPermissionsPreferenceController.java +++ b/src/com/android/settings/applications/AppPermissionsPreferenceController.java @@ -16,38 +16,47 @@ package com.android.settings.applications; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; import android.icu.text.ListFormatter; import android.util.ArraySet; -import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.applications.PermissionsSummaryHelper; -import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; public class AppPermissionsPreferenceController extends BasePreferenceController { private static final String TAG = "AppPermissionPrefCtrl"; - private static final String[] PERMISSION_GROUPS = new String[]{ - "android.permission-group.LOCATION", - "android.permission-group.MICROPHONE", - "android.permission-group.CAMERA", - "android.permission-group.SMS", - "android.permission-group.CONTACTS", - "android.permission-group.PHONE"}; - - private static final int NUM_PERMISSION_TO_USE = 3; + private static int NUM_PACKAGE_TO_CHECK = 3; private final PackageManager mPackageManager; + private final Set mPermissionGroups; + + private final PermissionsSummaryHelper.PermissionsResultCallback mPermissionsCallback = + new PermissionsSummaryHelper.PermissionsResultCallback() { + @Override + public void onPermissionSummaryResult(int standardGrantedPermissionCount, + int requestedPermissionCount, int additionalGrantedPermissionCount, + List grantedGroupLabels) { + updateSummary(grantedGroupLabels); + } + }; + + @VisibleForTesting + int mNumPackageChecked; + + private Preference mPreference; public AppPermissionsPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mPackageManager = context.getPackageManager(); + mPermissionGroups = new ArraySet<>(); } @Override @@ -55,72 +64,41 @@ public class AppPermissionsPreferenceController extends BasePreferenceController return AVAILABLE; } - /* - Summary text looks like: Apps using Permission1, Permission2, Permission3 - The 3 permissions are the first three from the list which any app has granted: - Location, Microphone, Camera, Sms, Contacts, and Phone - */ @Override - public CharSequence getSummary() { - final Set permissions = getAllPermissionsInGroups(); - Set grantedPermissionGroups = getGrantedPermissionGroups(permissions); - int count = 0; - final List summaries = new ArrayList<>(); - - for (String group : PERMISSION_GROUPS) { - if (!grantedPermissionGroups.contains(group)) { - continue; - } - summaries.add(getPermissionGroupLabel(group).toString().toLowerCase()); - if (++count >= NUM_PERMISSION_TO_USE) { - break; - } - } - return count > 0 ? mContext.getString(R.string.app_permissions_summary, - ListFormatter.getInstance().format(summaries)) : null; + public void updateState(Preference preference) { + mPreference = preference; + mNumPackageChecked = 0; + queryPermissionSummary(); } - private Set getGrantedPermissionGroups(Set permissions) { - ArraySet grantedPermissionGroups = new ArraySet<>(); - List installedPackages = + @VisibleForTesting + void queryPermissionSummary() { + final List installedPackages = mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS); - for (PackageInfo installedPackage : installedPackages) { - if (installedPackage.permissions == null) { - continue; - } - for (PermissionInfo permissionInfo : installedPackage.permissions) { - if (permissions.contains(permissionInfo.name) - && !grantedPermissionGroups.contains(permissionInfo.group)) { - grantedPermissionGroups.add(permissionInfo.group); - } - } + // Here we only get the first three apps and check their permissions. + final List packagesWithPermission = installedPackages.stream() + .filter(pInfo -> pInfo.permissions != null) + .limit(NUM_PACKAGE_TO_CHECK) + .collect(Collectors.toList()); + + for (PackageInfo installedPackage : packagesWithPermission) { + PermissionsSummaryHelper.getPermissionSummary(mContext, + installedPackage.packageName, mPermissionsCallback); } - return grantedPermissionGroups; } - private CharSequence getPermissionGroupLabel(String group) { - try { - final PermissionGroupInfo groupInfo = mPackageManager.getPermissionGroupInfo(group, 0); - return groupInfo.loadLabel(mPackageManager); - } catch (NameNotFoundException e) { - Log.e(TAG, "Error getting permissions label.", e); - } - return group; - } + @VisibleForTesting + void updateSummary(List grantedGroupLabels) { + mPermissionGroups.addAll(grantedGroupLabels); + mNumPackageChecked++; - private Set getAllPermissionsInGroups() { - ArraySet result = new ArraySet<>(); - for (String group : PERMISSION_GROUPS) { - try { - final List permissions = - mPackageManager.queryPermissionsByGroup(group, 0); - for (PermissionInfo permissionInfo : permissions) { - result.add(permissionInfo.name); - } - } catch (NameNotFoundException e) { - Log.e(TAG, "Error getting permissions in group " + group, e); - } + if (mNumPackageChecked < NUM_PACKAGE_TO_CHECK) { + return; } - return result; + final CharSequence summary = !mPermissionGroups.isEmpty() + ? mContext.getString(R.string.app_permissions_summary, + ListFormatter.getInstance().format(mPermissionGroups).toLowerCase()) + : null; + mPreference.setSummary(summary); } -} +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java index 4343e16143e..107821c15f0 100644 --- a/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java @@ -18,130 +18,38 @@ package com.android.settings.applications; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; import androidx.preference.Preference; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; -import java.util.List; @RunWith(RobolectricTestRunner.class) public class AppPermissionsPreferenceControllerTest { - private static final String PERM_LOCATION = "android.permission-group.LOCATION"; - private static final String PERM_MICROPHONE = "android.permission-group.MICROPHONE"; - private static final String PERM_CAMERA = "android.permission-group.CAMERA"; - private static final String PERM_SMS = "android.permission-group.SMS"; - private static final String PERM_CONTACTS = "android.permission-group.CONTACTS"; - private static final String PERM_PHONE = "android.permission-group.PHONE"; - private static final String LABEL_LOCATION = "Location"; - private static final String LABEL_MICROPHONE = "Microphone"; - private static final String LABEL_CAMERA = "Camera"; - private static final String LABEL_SMS = "Sms"; - private static final String LABEL_CONTACTS = "Contacts"; - private static final String LABEL_PHONE = "Phone"; - - @Mock - private Preference mPreference; - @Mock - private PackageManager mPackageManager; - @Mock - private PermissionGroupInfo mGroupLocation; - @Mock - private PermissionGroupInfo mGroupMic; - @Mock - private PermissionGroupInfo mGroupCamera; - @Mock - private PermissionGroupInfo mGroupSms; - @Mock - private PermissionGroupInfo mGroupContacts; - @Mock - private PermissionGroupInfo mGroupPhone; - private Context mContext; private AppPermissionsPreferenceController mController; - private PermissionInfo mPermLocation; - private PermissionInfo mPermMic; - private PermissionInfo mPermCamera; - private PermissionInfo mPermSms; - private PermissionInfo mPermContacts; - private PermissionInfo mPermPhone; + private Preference mPreference; @Before public void setUp() throws NameNotFoundException { MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - when(mContext.getPackageManager()).thenReturn(mPackageManager); - - // create permission groups - when(mPackageManager.getPermissionGroupInfo(eq(PERM_LOCATION), anyInt())) - .thenReturn(mGroupLocation); - when(mGroupLocation.loadLabel(mPackageManager)).thenReturn(LABEL_LOCATION); - when(mPackageManager.getPermissionGroupInfo(eq(PERM_MICROPHONE), anyInt())) - .thenReturn(mGroupMic); - when(mGroupMic.loadLabel(mPackageManager)).thenReturn(LABEL_MICROPHONE); - when(mPackageManager.getPermissionGroupInfo(eq(PERM_CAMERA), anyInt())) - .thenReturn(mGroupCamera); - when(mGroupCamera.loadLabel(mPackageManager)).thenReturn(LABEL_CAMERA); - when(mPackageManager.getPermissionGroupInfo(eq(PERM_SMS), anyInt())).thenReturn(mGroupSms); - when(mGroupSms.loadLabel(mPackageManager)).thenReturn(LABEL_SMS); - when(mPackageManager.getPermissionGroupInfo(eq(PERM_CONTACTS), anyInt())) - .thenReturn(mGroupContacts); - when(mGroupContacts.loadLabel(mPackageManager)).thenReturn(LABEL_CONTACTS); - when(mPackageManager.getPermissionGroupInfo(eq(PERM_PHONE), anyInt())) - .thenReturn(mGroupPhone); - when(mGroupPhone.loadLabel(mPackageManager)).thenReturn(LABEL_PHONE); - - // create permissions - mPermLocation = new PermissionInfo(); - mPermLocation.name = "Permission1"; - mPermLocation.group = PERM_LOCATION; - mPermMic = new PermissionInfo(); - mPermMic.name = "Permission2"; - mPermMic.group = PERM_MICROPHONE; - mPermCamera = new PermissionInfo(); - mPermCamera.name = "Permission3"; - mPermCamera.group = PERM_CAMERA; - mPermSms = new PermissionInfo(); - mPermSms.name = "Permission4"; - mPermSms.group = PERM_SMS; - mPermContacts = new PermissionInfo(); - mPermContacts.name = "Permission4"; - mPermContacts.group = PERM_CONTACTS; - mPermPhone = new PermissionInfo(); - mPermPhone.name = "Permission4"; - mPermPhone.group = PERM_PHONE; - final List permissions = new ArrayList<>(); - permissions.add(mPermLocation); - permissions.add(mPermMic); - permissions.add(mPermCamera); - permissions.add(mPermSms); - permissions.add(mPermContacts); - permissions.add(mPermPhone); - when(mPackageManager.queryPermissionsByGroup(anyString(), anyInt())) - .thenReturn(permissions); - + mContext = RuntimeEnvironment.application; + mPreference = spy(new Preference(mContext)); mController = spy(new AppPermissionsPreferenceController(mContext, "pref_key")); } @@ -151,65 +59,51 @@ public class AppPermissionsPreferenceControllerTest { } @Test - public void updateState_noGrantedPermissions_shouldNotSetSummary() { - final List installedPackages = new ArrayList<>(); - final PackageInfo info = new PackageInfo(); - installedPackages.add(info); - when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)) - .thenReturn(installedPackages); + public void updateState_shouldResetNumPackageChecked() { + doNothing().when(mController).queryPermissionSummary(); + mController.mNumPackageChecked = 3; mController.updateState(mPreference); - verify(mPreference, never()).setSummary(anyString()); + assertThat(mController.mNumPackageChecked).isEqualTo(0); } @Test - public void updateState_hasPermissions_shouldSetSummary() { - final List installedPackages = new ArrayList<>(); - final PackageInfo info = new PackageInfo(); - installedPackages.add(info); - when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)) - .thenReturn(installedPackages); - PermissionInfo[] permissions = new PermissionInfo[4]; - info.permissions = permissions; - - permissions[0] = mPermLocation; - permissions[1] = mPermMic; - permissions[2] = mPermCamera; - permissions[3] = mPermSms; + public void updateSummary_noGrantedPermission_shouldSetNullSummary() { + doNothing().when(mController).queryPermissionSummary(); mController.updateState(mPreference); + mController.mNumPackageChecked = 2; - verify(mPreference).setSummary("Apps using location, microphone, and camera"); + mController.updateSummary(new ArrayList<>()); - permissions[0] = mPermPhone; - permissions[1] = mPermMic; - permissions[2] = mPermCamera; - permissions[3] = mPermSms; + assertThat(mPreference.getSummary()).isNull(); + } + + @Test + public void updateSummary_hasPermissionGroups_shouldSetPermissionAsSummary() { + doNothing().when(mController).queryPermissionSummary(); mController.updateState(mPreference); + final String permission = "location"; + final ArrayList labels = new ArrayList<>(); + labels.add(permission); + final String summary = "Apps using " + permission; + mController.mNumPackageChecked = 2; - verify(mPreference).setSummary("Apps using microphone, camera, and sms"); + mController.updateSummary(labels); - permissions[0] = mPermPhone; - permissions[1] = mPermMic; - permissions[2] = mPermContacts; - permissions[3] = mPermSms; + assertThat(mPreference.getSummary()).isEqualTo(summary); + } + + @Test + public void updateSummary_notReachCallbackCount_shouldNotSetSummary() { + doNothing().when(mController).queryPermissionSummary(); mController.updateState(mPreference); + final String permission = "location"; + final ArrayList labels = new ArrayList<>(); + labels.add(permission); - verify(mPreference).setSummary("Apps using microphone, sms, and contacts"); + mController.updateSummary(labels); - permissions = new PermissionInfo[2]; - info.permissions = permissions; - permissions[0] = mPermLocation; - permissions[1] = mPermCamera; - mController.updateState(mPreference); - - verify(mPreference).setSummary("Apps using location and camera"); - - permissions = new PermissionInfo[1]; - info.permissions = permissions; - permissions[0] = mPermCamera; - mController.updateState(mPreference); - - verify(mPreference).setSummary("Apps using camera"); + verify(mPreference, never()).setSummary(anyString()); } }