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()); } }