diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml index c0c48407726..623460c5d37 100644 --- a/res/xml/privacy_dashboard_settings.xml +++ b/res/xml/privacy_dashboard_settings.xml @@ -22,12 +22,6 @@ android:title="@string/privacy_dashboard_title" settings:initialExpandedChildrenCount="4"> - - mOldUsageInfos; - private PackageManager mPackageManager; - private PrivacyDashboardFragment mParent; - private BarChartPreference mBarChartPreference; - - public PermissionBarChartPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - mOldUsageInfos = new ArrayList<>(); - mPackageManager = context.getPackageManager(); - } - - public void setFragment(PrivacyDashboardFragment fragment) { - mParent = fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - if (savedInstanceState != null) { - mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos); - } - - @Override - public int getAvailabilityStatus() { - return Boolean.parseBoolean( - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PRIVACY, - com.android.settings.Utils.PROPERTY_PERMISSIONS_HUB_ENABLED)) ? - AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mBarChartPreference = screen.findPreference(getPreferenceKey()); - - final BarChartInfo info = new BarChartInfo.Builder() - .setTitle(R.string.permission_bar_chart_title) - .setDetails(R.string.permission_bar_chart_details) - .setEmptyText(R.string.permission_bar_chart_empty_text) - .setDetailsOnClickListener((View v) -> { - final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE); - intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1)); - mContext.startActivity(intent); - }) - .build(); - - mBarChartPreference.initializeBarChart(info); - if (!mOldUsageInfos.isEmpty()) { - mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos)); - } - } - - @Override - public void onStart() { - if (!isAvailable()) { - return; - } - - // Add a shadow animation to action bar scroll only when the chart is available. - com.android.settings.Utils.setActionBarShadowAnimation(mParent.getActivity(), - mParent.getSettingsLifecycle(), mParent.getListView()); - // We don't hide chart when we have existing data. - mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */); - // But we still need to hint user with progress bar that we are updating new usage data. - mParent.showPinnedHeader(true); - retrievePermissionUsageData(); - } - - @Override - public void onPermissionUsageResult(@NonNull List usageInfos) { - usageInfos.sort((x, y) -> { - int usageDiff = y.getAppAccessCount() - x.getAppAccessCount(); - if (usageDiff != 0) { - return usageDiff; - } - String xName = x.getName(); - String yName = y.getName(); - if (xName.equals(LOCATION)) { - return -1; - } else if (yName.equals(LOCATION)) { - return 1; - } else if (xName.equals(MICROPHONE)) { - return -1; - } else if (yName.equals(MICROPHONE)) { - return 1; - } else if (xName.equals(CAMERA)) { - return -1; - } else if (yName.equals(CAMERA)) { - return 1; - } - return x.getName().compareTo(y.getName()); - }); - - // If the result is different, we need to update bar views. - if (!areSamePermissionGroups(usageInfos)) { - mBarChartPreference.setBarViewInfos(createBarViews(usageInfos)); - mOldUsageInfos = usageInfos; - } - - mBarChartPreference.updateLoadingState(false /* isLoading */); - mParent.showPinnedHeader(false); - } - - private void retrievePermissionUsageData() { - mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages( - false /* countSystem */, (int) DAYS.toMillis(1), - mContext.getMainExecutor() /* executor */, this /* callback */); - } - - private BarViewInfo[] createBarViews(List usageInfos) { - if (usageInfos.isEmpty()) { - return null; - } - - final BarViewInfo[] barViewInfos = new BarViewInfo[ - Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())]; - - for (int index = 0; index < barViewInfos.length; index++) { - final RuntimePermissionUsageInfo permissionGroupInfo = usageInfos.get(index); - final int count = permissionGroupInfo.getAppAccessCount(); - final CharSequence permLabel = getPermissionGroupLabel(permissionGroupInfo.getName()); - - barViewInfos[index] = new BarViewInfo( - getPermissionGroupIcon(permissionGroupInfo.getName()), count, permLabel, - mContext.getResources().getQuantityString(R.plurals.permission_bar_chart_label, - count, count), permLabel); - - // Set the click listener for each bar view. - // The listener will navigate user to permission usage app. - barViewInfos[index].setClickListener((View v) -> { - final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE); - intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName()); - intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1)); - mContext.startActivity(intent); - }); - } - - return barViewInfos; - } - - private Drawable getPermissionGroupIcon(String permissionGroup) { - Drawable icon = null; - try { - icon = mPackageManager.getPermissionGroupInfo(permissionGroup, 0) - .loadIcon(mPackageManager); - icon.setTintList(Utils.getColorAttr(mContext, android.R.attr.textColorSecondary)); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Cannot find group icon for " + permissionGroup, e); - } - - return icon; - } - - private CharSequence getPermissionGroupLabel(String permissionGroup) { - CharSequence label = null; - try { - label = mPackageManager.getPermissionGroupInfo(permissionGroup, 0) - .loadLabel(mPackageManager); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Cannot find group label for " + permissionGroup, e); - } - - return label; - } - - private boolean areSamePermissionGroups(List newUsageInfos) { - if (newUsageInfos.size() != mOldUsageInfos.size()) { - return false; - } - - for (int index = 0; index < newUsageInfos.size(); index++) { - final RuntimePermissionUsageInfo newInfo = newUsageInfos.get(index); - final RuntimePermissionUsageInfo oldInfo = mOldUsageInfos.get(index); - - if (!newInfo.getName().equals(oldInfo.getName()) || - newInfo.getAppAccessCount() != oldInfo.getAppAccessCount()) { - return false; - } - } - return true; - } -} diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java index c7c564d3369..cc0e8a153b7 100644 --- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java +++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java @@ -18,10 +18,6 @@ package com.android.settings.privacy; import android.app.settings.SettingsEnums; import android.content.Context; -import android.os.Bundle; -import android.view.View; - -import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; @@ -68,24 +64,6 @@ public class PrivacyDashboardFragment extends DashboardFragment { return buildPreferenceControllers(context, getSettingsLifecycle()); } - @Override - public void onAttach(Context context) { - super.onAttach(context); - use(PermissionBarChartPreferenceController.class).setFragment(this /* fragment */); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - initLoadingBar(); - } - - @VisibleForTesting - void initLoadingBar() { - setPinnedHeaderView(R.layout.progress_header); - showPinnedHeader(false); - } - private static List buildPreferenceControllers( Context context, Lifecycle lifecycle) { final List controllers = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java deleted file mode 100644 index 5501aa449a2..00000000000 --- a/tests/robotests/src/com/android/settings/privacy/PermissionBarChartPreferenceControllerTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.privacy; - -import static android.Manifest.permission_group.CALENDAR; -import static android.Manifest.permission_group.CAMERA; -import static android.Manifest.permission_group.CONTACTS; -import static android.Manifest.permission_group.LOCATION; -import static android.Manifest.permission_group.MICROPHONE; -import static android.Manifest.permission_group.PHONE; -import static android.Manifest.permission_group.SMS; - -import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; -import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.UserInfo; -import android.os.UserManager; -import android.permission.RuntimePermissionUsageInfo; -import android.provider.DeviceConfig; -import android.view.accessibility.AccessibilityManager; - -import androidx.preference.PreferenceScreen; - -import com.android.internal.widget.LockPatternUtils; -import com.android.settings.Utils; -import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.shadow.ShadowDeviceConfig; -import com.android.settings.testutils.shadow.ShadowPermissionControllerManager; -import com.android.settings.testutils.shadow.ShadowUserManager; -import com.android.settingslib.widget.BarChartInfo; -import com.android.settingslib.widget.BarChartPreference; -import com.android.settingslib.widget.BarViewInfo; - -import org.junit.After; -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 org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowAccessibilityManager; -import org.robolectric.shadows.androidx.fragment.FragmentController; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowDeviceConfig.class, ShadowUserManager.class, - ShadowPermissionControllerManager.class}) -public class PermissionBarChartPreferenceControllerTest { - - @Mock - private PreferenceScreen mScreen; - @Mock - private LockPatternUtils mLockPatternUtils; - - private PermissionBarChartPreferenceController mController; - private BarChartPreference mPreference; - private PrivacyDashboardFragment mFragment; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - final Context context = RuntimeEnvironment.application; - final UserManager userManager = context.getSystemService(UserManager.class); - final ShadowUserManager shadowUserManager = Shadow.extract(userManager); - final ShadowAccessibilityManager accessibilityManager = Shadow.extract( - AccessibilityManager.getInstance(context)); - accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>()); - shadowUserManager.addProfile(new UserInfo(123, null, 0)); - when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils( - any(Context.class))).thenReturn(mLockPatternUtils); - - mController = spy(new PermissionBarChartPreferenceController(context, "test_key")); - mFragment = spy(FragmentController.of(new PrivacyDashboardFragment()) - .create().start().get()); - mController.setFragment(mFragment); - mPreference = spy(new BarChartPreference(context)); - when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); - } - - @After - public void tearDown() { - ShadowDeviceConfig.reset(); - } - - @Test - public void getAvailabilityStatus_permissionHubNotSet_shouldReturnUnsupported() { - // We have not yet set the property to show the Permissions Hub. - assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); - } - - @Test - public void getAvailabilityStatus_permissionHubEnabled_shouldReturnAvailableUnsearchable() { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, - Utils.PROPERTY_PERMISSIONS_HUB_ENABLED, - "true", true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); - } - - @Test - public void displayPreference_shouldInitializeBarChart() { - mController.displayPreference(mScreen); - - verify(mPreference).initializeBarChart(any(BarChartInfo.class)); - } - - @Test - public void displayPreference_usageInfosSet_shouldSetBarViewInfos() { - final RuntimePermissionUsageInfo info1 = - new RuntimePermissionUsageInfo("permission 1", 10); - mController.mOldUsageInfos.add(info1); - - mController.displayPreference(mScreen); - - verify(mPreference).setBarViewInfos(any(BarViewInfo[].class)); - verify(mPreference).initializeBarChart(any(BarChartInfo.class)); - } - - @Test - public void onPermissionUsageResult_differentPermissionResultSet_shouldSetBarViewInfos() { - final List infos1 = new ArrayList<>(); - final RuntimePermissionUsageInfo info1 = - new RuntimePermissionUsageInfo("permission 1", 10); - infos1.add(info1); - mController.displayPreference(mScreen); - mController.onPermissionUsageResult(infos1); - - verify(mPreference).setBarViewInfos(any(BarViewInfo[].class)); - - final List infos2 = new ArrayList<>(); - final RuntimePermissionUsageInfo info2 = - new RuntimePermissionUsageInfo("permission 2", 20); - infos2.add(info2); - mController.onPermissionUsageResult(infos2); - - verify(mPreference, times(2)).setBarViewInfos(any(BarViewInfo[].class)); - } - - @Test - public void onPermissionUsageResult_samePermissionResultSet_shouldNotSetBarViewInfos() { - final List mInfos = new ArrayList<>(); - final RuntimePermissionUsageInfo info1 = - new RuntimePermissionUsageInfo("permission 1", 10); - mInfos.add(info1); - mController.displayPreference(mScreen); - mController.onPermissionUsageResult(mInfos); - - mController.onPermissionUsageResult(mInfos); - - verify(mPreference, times(1)).setBarViewInfos(any(BarViewInfo[].class)); - } - - @Test - public void onStart_usageInfosNotSetAndPermissionHubEnabled_shouldShowProgressBar() { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, - Utils.PROPERTY_PERMISSIONS_HUB_ENABLED, - "true", true); - mController.displayPreference(mScreen); - - mController.onStart(); - - assertThat(mFragment.getActivity().getActionBar().getElevation()).isZero(); - verify(mFragment).showPinnedHeader(true); - verify(mPreference).updateLoadingState(true /* isLoading */); - } - - @Test - public void onStart_usageInfosSetAndPermissionHubEnabled_shouldNotUpdatePrefLoadingState() { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, - Utils.PROPERTY_PERMISSIONS_HUB_ENABLED, - "true", true); - final RuntimePermissionUsageInfo info1 = - new RuntimePermissionUsageInfo("permission 1", 10); - mController.mOldUsageInfos.add(info1); - mController.displayPreference(mScreen); - - mController.onStart(); - - assertThat(mFragment.getActivity().getActionBar().getElevation()).isZero(); - verify(mFragment).showPinnedHeader(true); - verify(mPreference).updateLoadingState(false /* isLoading */); - } - - @Test - public void onStart_permissionHubDisabled_shouldNotShowProgressBar() { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, - Utils.PROPERTY_PERMISSIONS_HUB_ENABLED, - "false", true); - - mController.onStart(); - - assertThat(mFragment.getActivity().getActionBar().getElevation()).isNonZero(); - verify(mFragment, never()).showPinnedHeader(true); - verify(mPreference, never()).updateLoadingState(true /* isLoading */); - } - - @Test - public void onPermissionUsageResult_shouldHideProgressBar() { - final List infos1 = new ArrayList<>(); - final RuntimePermissionUsageInfo info1 = - new RuntimePermissionUsageInfo("permission 1", 10); - infos1.add(info1); - mController.displayPreference(mScreen); - - mController.onPermissionUsageResult(infos1); - - verify(mFragment).showPinnedHeader(false); - verify(mPreference).updateLoadingState(false /* isLoading */); - } - - @Test - public void onPermissionUsageResult_shouldBeSorted() { - final List infos = new ArrayList<>(); - infos.add(new RuntimePermissionUsageInfo(PHONE, 10)); - infos.add(new RuntimePermissionUsageInfo(LOCATION, 10)); - infos.add(new RuntimePermissionUsageInfo(CAMERA, 10)); - infos.add(new RuntimePermissionUsageInfo(SMS, 1)); - infos.add(new RuntimePermissionUsageInfo(MICROPHONE, 10)); - infos.add(new RuntimePermissionUsageInfo(CONTACTS, 42)); - infos.add(new RuntimePermissionUsageInfo(CALENDAR, 10)); - mController.displayPreference(mScreen); - - mController.onPermissionUsageResult(infos); - - assertThat(infos.get(0).getName()).isEqualTo(CONTACTS); - assertThat(infos.get(1).getName()).isEqualTo(LOCATION); - assertThat(infos.get(2).getName()).isEqualTo(MICROPHONE); - assertThat(infos.get(3).getName()).isEqualTo(CAMERA); - assertThat(infos.get(4).getName()).isEqualTo(CALENDAR); - assertThat(infos.get(5).getName()).isEqualTo(PHONE); - assertThat(infos.get(6).getName()).isEqualTo(SMS); - } -} diff --git a/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java deleted file mode 100644 index 256fcd4a779..00000000000 --- a/tests/robotests/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.privacy; - -import static org.mockito.ArgumentMatchers.any; -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.UserInfo; -import android.os.Bundle; -import android.os.UserManager; -import android.view.View; -import android.view.accessibility.AccessibilityManager; - -import com.android.internal.widget.LockPatternUtils; -import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.shadow.ShadowPermissionControllerManager; -import com.android.settings.testutils.shadow.ShadowUserManager; - -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 org.robolectric.annotation.Config; -import org.robolectric.shadow.api.Shadow; -import org.robolectric.shadows.ShadowAccessibilityManager; -import org.robolectric.shadows.androidx.fragment.FragmentController; - -import java.util.ArrayList; - - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowUserManager.class, ShadowPermissionControllerManager.class}) -public class PrivacyDashboardFragmentTest { - - @Mock - private LockPatternUtils mLockPatternUtils; - - private Context mContext; - private PrivacyDashboardFragment mFragment; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - final UserManager userManager = mContext.getSystemService(UserManager.class); - final ShadowUserManager shadowUserManager = Shadow.extract(userManager); - final ShadowAccessibilityManager accessibilityManager = Shadow.extract( - AccessibilityManager.getInstance(mContext)); - accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>()); - shadowUserManager.addProfile(new UserInfo(123, null, 0)); - when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils( - any(Context.class))).thenReturn(mLockPatternUtils); - mFragment = spy(FragmentController.of(new PrivacyDashboardFragment()) - .create().start().get()); - } - - @Test - public void onViewCreated_shouldInitLinearProgressBar() { - mFragment.onViewCreated(new View(mContext), new Bundle()); - - verify(mFragment).initLoadingBar(); - } -}