From 62b15ac6694f5132453ae0c711bcbb790acf1b47 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Thu, 11 Jun 2020 12:36:53 +0800 Subject: [PATCH] Update App info behavior for mainline module As requested by framework team, the mainline module should be considered as system apps and not stoppable and disable-able. Since many of these modules provide critical functionality, disabling them can result in a very unstable device. According to the request, Settings will apply below changes to App info page for protecting mainline modules: - Hide "Force stop" and "Disable" in App info. - Disable "Clear storage" and "Clear cache" in "Storage & cache". Since the mainline module checking API interface changed, also change the dependent files and test cases. Fixes: 156955322 Test: robotest and verify "Cell Broadcast Service" in App info Change-Id: Ibc239bdaf3364eda541a33add382364cfdc6fc9b --- .../applications/AppStorageSettings.java | 5 +- .../AppButtonsPreferenceController.java | 4 +- .../AppInstallerInfoPreferenceController.java | 2 +- .../applications/AppStorageSettingsTest.java | 53 +++++++++++++++++-- .../AppButtonsPreferenceControllerTest.java | 24 +++++++++ ...InstallerInfoPreferenceControllerTest.java | 30 +++++++++-- 6 files changed, 107 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java index f07c66cd8a5..8a54c730e10 100644 --- a/src/com/android/settings/applications/AppStorageSettings.java +++ b/src/com/android/settings/applications/AppStorageSettings.java @@ -54,6 +54,7 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.deviceinfo.StorageWizardMoveConfirm; import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource.AppStorageStats; @@ -321,7 +322,7 @@ public class AppStorageSettings extends AppInfoWithHeader .setButton1OnClickListener(v -> handleClearDataClick()); } - if (mAppsControlDisallowedBySystem) { + if (mAppsControlDisallowedBySystem || AppUtils.isMainlineModule(mPm, mPackageName)) { mButtonsPref.setButton1Enabled(false); } } @@ -579,7 +580,7 @@ public class AppStorageSettings extends AppInfoWithHeader .setButton2OnClickListener(v -> handleClearCacheClick()); } } - if (mAppsControlDisallowedBySystem) { + if (mAppsControlDisallowedBySystem || AppUtils.isMainlineModule(mPm, mPackageName)) { mButtonsPref.setButton1Enabled(false).setButton2Enabled(false); } } diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index 147c412f92c..36ad2ce9746 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -744,7 +744,9 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp } private boolean isSystemModule() { - return mAppEntry != null && AppUtils.isSystemModule(mContext, mAppEntry.info.packageName); + return mAppEntry != null + && (AppUtils.isSystemModule(mContext, mAppEntry.info.packageName) + || AppUtils.isMainlineModule(mPm, mAppEntry.info.packageName)); } /** diff --git a/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java b/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java index 2e119537a2c..5e99e8bedb1 100644 --- a/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java @@ -43,7 +43,7 @@ public class AppInstallerInfoPreferenceController extends AppInfoPreferenceContr return DISABLED_FOR_USER; } - if (AppUtils.isMainlineModule(mContext, mPackageName)) { + if (AppUtils.isMainlineModule(mContext.getPackageManager(), mPackageName)) { return DISABLED_FOR_USER; } diff --git a/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java index 35177024b38..2027ace9ead 100644 --- a/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java @@ -16,9 +16,9 @@ package com.android.settings.applications; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -28,6 +28,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.ModuleInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.view.View; import android.widget.Button; @@ -51,6 +55,8 @@ public class AppStorageSettingsTest { private AppStorageSettings mSettings; private Button mLeftButton; private Button mRightButton; + @Mock + private PackageManager mPackageManager; @Before public void setUp() { @@ -58,6 +64,8 @@ public class AppStorageSettingsTest { mLeftButton = new Button(RuntimeEnvironment.application); mRightButton = new Button(RuntimeEnvironment.application); mSettings = spy(new AppStorageSettings()); + mSettings.mPm = mPackageManager; + mSettings.mPackageName = "Package"; mSettings.mSizeController = mSizesController; mButtonsPref = createMock(); mSettings.mButtonsPref = mButtonsPref; @@ -77,7 +85,9 @@ public class AppStorageSettingsTest { } @Test - public void updateUiWithSize_noAppStats_shouldDisableClearButtons() { + public void updateUiWithSize_noAppStats_shouldDisableClearButtons() + throws PackageManager.NameNotFoundException { + mockMainlineModule(mSettings.mPackageName, false /* isMainlineModule */); mSettings.updateUiWithSize(null); verify(mSizesController).updateUi(nullable(Context.class)); @@ -86,12 +96,15 @@ public class AppStorageSettingsTest { } @Test - public void updateUiWithSize_hasDataAndCache_shouldEnableClearButtons() { + public void updateUiWithSize_hasDataAndCache_shouldEnableClearButtons() + throws PackageManager.NameNotFoundException { final AppStorageStats stats = mock(AppStorageStats.class); when(stats.getCacheBytes()).thenReturn(5000L); when(stats.getDataBytes()).thenReturn(10000L); doNothing().when(mSettings).handleClearCacheClick(); doNothing().when(mSettings).handleClearDataClick(); + mockMainlineModule(mSettings.mPackageName, false /* isMainlineModule */); + mSettings.updateUiWithSize(stats); verify(mButtonsPref).setButton1Enabled(true); @@ -105,6 +118,22 @@ public class AppStorageSettingsTest { verify(mSettings).handleClearCacheClick(); } + @Test + public void updateUiWithSize_mainlineModule_shouldDisableClearButtons() + throws PackageManager.NameNotFoundException { + final AppStorageStats stats = mock(AppStorageStats.class); + when(stats.getCacheBytes()).thenReturn(5000L); + when(stats.getDataBytes()).thenReturn(10000L); + doNothing().when(mSettings).handleClearCacheClick(); + doNothing().when(mSettings).handleClearDataClick(); + mockMainlineModule(mSettings.mPackageName, true /* isMainlineModule */); + + + mSettings.updateUiWithSize(stats); + verify(mButtonsPref).setButton1Enabled(false); + verify(mButtonsPref).setButton2Enabled(false); + } + private ActionButtonsPreference createMock() { final ActionButtonsPreference pref = mock(ActionButtonsPreference.class); when(pref.setButton1Text(anyInt())).thenReturn(pref); @@ -121,5 +150,23 @@ public class AppStorageSettingsTest { return pref; } + + private void mockMainlineModule(String packageName, boolean isMainlineModule) + throws PackageManager.NameNotFoundException { + final PackageInfo packageInfo = new PackageInfo(); + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.sourceDir = "apex"; + packageInfo.applicationInfo = applicationInfo; + + if (isMainlineModule) { + when(mPackageManager.getModuleInfo(packageName, 0 /* flags */)).thenReturn( + new ModuleInfo()); + } else { + when(mPackageManager.getPackageInfo(packageName, 0 /* flags */)).thenReturn( + packageInfo); + when(mPackageManager.getModuleInfo(packageName, 0 /* flags */)).thenThrow( + new PackageManager.NameNotFoundException()); + } + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java index c2bcd1c7793..a5ac209b941 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -543,6 +543,19 @@ public class AppButtonsPreferenceControllerTest { assertThat(i.getBooleanExtra(KEY_REMOVE_TASK_WHEN_FINISHING, false)).isFalse(); } + @Test + @Config(shadows = ShadowAppUtils.class) + public void isAvailable_nonMainlineModule_isTrue() { + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + @Config(shadows = ShadowAppUtils.class) + public void isAvailable_mainlineModule_isFalse() { + ShadowAppUtils.addMainlineModule(mController.mPackageName); + assertThat(mController.isAvailable()).isFalse(); + } + /** * The test fragment which implements * {@link ButtonActionDialogFragment.AppButtonsDialogListener} @@ -597,16 +610,22 @@ public class AppButtonsPreferenceControllerTest { public static class ShadowAppUtils { public static Set sSystemModules = new ArraySet<>(); + public static Set sMainlineModules = new ArraySet<>(); @Resetter public static void reset() { sSystemModules.clear(); + sMainlineModules.clear(); } public static void addHiddenModule(String pkg) { sSystemModules.add(pkg); } + public static void addMainlineModule(String pkg) { + sMainlineModules.add(pkg); + } + @Implementation protected static boolean isInstant(ApplicationInfo info) { return false; @@ -616,5 +635,10 @@ public class AppButtonsPreferenceControllerTest { protected static boolean isSystemModule(Context context, String packageName) { return sSystemModules.contains(packageName); } + + @Implementation + protected static boolean isMainlineModule(PackageManager pm, String packageName) { + return sMainlineModules.contains(packageName); + } } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java index 00bd5f80724..d37a6850a54 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java @@ -99,12 +99,15 @@ public class AppInstallerInfoPreferenceControllerTest { } @Test - public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable() { + public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable() + throws PackageManager.NameNotFoundException { + final String packageName = "Package1"; when(mUserManager.isManagedProfile()).thenReturn(false); when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1"); mController = new AppInstallerInfoPreferenceController(mContext, "test_key"); - mController.setPackageName("Package1"); + mController.setPackageName(packageName); mController.setParentFragment(mFragment); + mockMainlineModule(packageName, false /* isMainlineModule */); assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.AVAILABLE); @@ -153,12 +156,31 @@ public class AppInstallerInfoPreferenceControllerTest { @Test public void getAvailabilityStatus_isMainlineModule_shouldReturnDisabled() throws PackageManager.NameNotFoundException { + final String packageName = "Package"; when(mUserManager.isManagedProfile()).thenReturn(false); when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label"); - mController.setPackageName("Package"); - when(mPackageManager.getModuleInfo("Package", 0 /* flags */)).thenReturn(new ModuleInfo()); + mController.setPackageName(packageName); + mockMainlineModule(packageName, true /* isMainlineModule */); assertThat(mController.getAvailabilityStatus()).isEqualTo( BasePreferenceController.DISABLED_FOR_USER); } + + private void mockMainlineModule(String packageName, boolean isMainlineModule) + throws PackageManager.NameNotFoundException { + final PackageInfo packageInfo = new PackageInfo(); + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.sourceDir = "apex"; + packageInfo.applicationInfo = applicationInfo; + + if (isMainlineModule) { + when(mPackageManager.getModuleInfo(packageName, 0 /* flags */)).thenReturn( + new ModuleInfo()); + } else { + when(mPackageManager.getPackageInfo(packageName, 0 /* flags */)).thenReturn( + packageInfo); + when(mPackageManager.getModuleInfo(packageName, 0 /* flags */)).thenThrow( + new PackageManager.NameNotFoundException()); + } + } }