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
This commit is contained in:
@@ -54,6 +54,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
|
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.applications.AppUtils;
|
||||||
import com.android.settingslib.applications.ApplicationsState.Callbacks;
|
import com.android.settingslib.applications.ApplicationsState.Callbacks;
|
||||||
import com.android.settingslib.applications.StorageStatsSource;
|
import com.android.settingslib.applications.StorageStatsSource;
|
||||||
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
|
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
|
||||||
@@ -321,7 +322,7 @@ public class AppStorageSettings extends AppInfoWithHeader
|
|||||||
.setButton1OnClickListener(v -> handleClearDataClick());
|
.setButton1OnClickListener(v -> handleClearDataClick());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAppsControlDisallowedBySystem) {
|
if (mAppsControlDisallowedBySystem || AppUtils.isMainlineModule(mPm, mPackageName)) {
|
||||||
mButtonsPref.setButton1Enabled(false);
|
mButtonsPref.setButton1Enabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -579,7 +580,7 @@ public class AppStorageSettings extends AppInfoWithHeader
|
|||||||
.setButton2OnClickListener(v -> handleClearCacheClick());
|
.setButton2OnClickListener(v -> handleClearCacheClick());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mAppsControlDisallowedBySystem) {
|
if (mAppsControlDisallowedBySystem || AppUtils.isMainlineModule(mPm, mPackageName)) {
|
||||||
mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
|
mButtonsPref.setButton1Enabled(false).setButton2Enabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -744,7 +744,9 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSystemModule() {
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -43,7 +43,7 @@ public class AppInstallerInfoPreferenceController extends AppInfoPreferenceContr
|
|||||||
return DISABLED_FOR_USER;
|
return DISABLED_FOR_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppUtils.isMainlineModule(mContext, mPackageName)) {
|
if (AppUtils.isMainlineModule(mContext.getPackageManager(), mPackageName)) {
|
||||||
return DISABLED_FOR_USER;
|
return DISABLED_FOR_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.applications;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.nullable;
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -28,6 +28,10 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
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.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
@@ -51,6 +55,8 @@ public class AppStorageSettingsTest {
|
|||||||
private AppStorageSettings mSettings;
|
private AppStorageSettings mSettings;
|
||||||
private Button mLeftButton;
|
private Button mLeftButton;
|
||||||
private Button mRightButton;
|
private Button mRightButton;
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -58,6 +64,8 @@ public class AppStorageSettingsTest {
|
|||||||
mLeftButton = new Button(RuntimeEnvironment.application);
|
mLeftButton = new Button(RuntimeEnvironment.application);
|
||||||
mRightButton = new Button(RuntimeEnvironment.application);
|
mRightButton = new Button(RuntimeEnvironment.application);
|
||||||
mSettings = spy(new AppStorageSettings());
|
mSettings = spy(new AppStorageSettings());
|
||||||
|
mSettings.mPm = mPackageManager;
|
||||||
|
mSettings.mPackageName = "Package";
|
||||||
mSettings.mSizeController = mSizesController;
|
mSettings.mSizeController = mSizesController;
|
||||||
mButtonsPref = createMock();
|
mButtonsPref = createMock();
|
||||||
mSettings.mButtonsPref = mButtonsPref;
|
mSettings.mButtonsPref = mButtonsPref;
|
||||||
@@ -77,7 +85,9 @@ public class AppStorageSettingsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateUiWithSize_noAppStats_shouldDisableClearButtons() {
|
public void updateUiWithSize_noAppStats_shouldDisableClearButtons()
|
||||||
|
throws PackageManager.NameNotFoundException {
|
||||||
|
mockMainlineModule(mSettings.mPackageName, false /* isMainlineModule */);
|
||||||
mSettings.updateUiWithSize(null);
|
mSettings.updateUiWithSize(null);
|
||||||
|
|
||||||
verify(mSizesController).updateUi(nullable(Context.class));
|
verify(mSizesController).updateUi(nullable(Context.class));
|
||||||
@@ -86,12 +96,15 @@ public class AppStorageSettingsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateUiWithSize_hasDataAndCache_shouldEnableClearButtons() {
|
public void updateUiWithSize_hasDataAndCache_shouldEnableClearButtons()
|
||||||
|
throws PackageManager.NameNotFoundException {
|
||||||
final AppStorageStats stats = mock(AppStorageStats.class);
|
final AppStorageStats stats = mock(AppStorageStats.class);
|
||||||
when(stats.getCacheBytes()).thenReturn(5000L);
|
when(stats.getCacheBytes()).thenReturn(5000L);
|
||||||
when(stats.getDataBytes()).thenReturn(10000L);
|
when(stats.getDataBytes()).thenReturn(10000L);
|
||||||
doNothing().when(mSettings).handleClearCacheClick();
|
doNothing().when(mSettings).handleClearCacheClick();
|
||||||
doNothing().when(mSettings).handleClearDataClick();
|
doNothing().when(mSettings).handleClearDataClick();
|
||||||
|
mockMainlineModule(mSettings.mPackageName, false /* isMainlineModule */);
|
||||||
|
|
||||||
|
|
||||||
mSettings.updateUiWithSize(stats);
|
mSettings.updateUiWithSize(stats);
|
||||||
verify(mButtonsPref).setButton1Enabled(true);
|
verify(mButtonsPref).setButton1Enabled(true);
|
||||||
@@ -105,6 +118,22 @@ public class AppStorageSettingsTest {
|
|||||||
verify(mSettings).handleClearCacheClick();
|
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() {
|
private ActionButtonsPreference createMock() {
|
||||||
final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
|
final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
|
||||||
when(pref.setButton1Text(anyInt())).thenReturn(pref);
|
when(pref.setButton1Text(anyInt())).thenReturn(pref);
|
||||||
@@ -121,5 +150,23 @@ public class AppStorageSettingsTest {
|
|||||||
|
|
||||||
return pref;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -543,6 +543,19 @@ public class AppButtonsPreferenceControllerTest {
|
|||||||
assertThat(i.getBooleanExtra(KEY_REMOVE_TASK_WHEN_FINISHING, false)).isFalse();
|
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
|
* The test fragment which implements
|
||||||
* {@link ButtonActionDialogFragment.AppButtonsDialogListener}
|
* {@link ButtonActionDialogFragment.AppButtonsDialogListener}
|
||||||
@@ -597,16 +610,22 @@ public class AppButtonsPreferenceControllerTest {
|
|||||||
public static class ShadowAppUtils {
|
public static class ShadowAppUtils {
|
||||||
|
|
||||||
public static Set<String> sSystemModules = new ArraySet<>();
|
public static Set<String> sSystemModules = new ArraySet<>();
|
||||||
|
public static Set<String> sMainlineModules = new ArraySet<>();
|
||||||
|
|
||||||
@Resetter
|
@Resetter
|
||||||
public static void reset() {
|
public static void reset() {
|
||||||
sSystemModules.clear();
|
sSystemModules.clear();
|
||||||
|
sMainlineModules.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addHiddenModule(String pkg) {
|
public static void addHiddenModule(String pkg) {
|
||||||
sSystemModules.add(pkg);
|
sSystemModules.add(pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addMainlineModule(String pkg) {
|
||||||
|
sMainlineModules.add(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
@Implementation
|
@Implementation
|
||||||
protected static boolean isInstant(ApplicationInfo info) {
|
protected static boolean isInstant(ApplicationInfo info) {
|
||||||
return false;
|
return false;
|
||||||
@@ -616,5 +635,10 @@ public class AppButtonsPreferenceControllerTest {
|
|||||||
protected static boolean isSystemModule(Context context, String packageName) {
|
protected static boolean isSystemModule(Context context, String packageName) {
|
||||||
return sSystemModules.contains(packageName);
|
return sSystemModules.contains(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
protected static boolean isMainlineModule(PackageManager pm, String packageName) {
|
||||||
|
return sMainlineModules.contains(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,12 +99,15 @@ public class AppInstallerInfoPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable() {
|
public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable()
|
||||||
|
throws PackageManager.NameNotFoundException {
|
||||||
|
final String packageName = "Package1";
|
||||||
when(mUserManager.isManagedProfile()).thenReturn(false);
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1");
|
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1");
|
||||||
mController = new AppInstallerInfoPreferenceController(mContext, "test_key");
|
mController = new AppInstallerInfoPreferenceController(mContext, "test_key");
|
||||||
mController.setPackageName("Package1");
|
mController.setPackageName(packageName);
|
||||||
mController.setParentFragment(mFragment);
|
mController.setParentFragment(mFragment);
|
||||||
|
mockMainlineModule(packageName, false /* isMainlineModule */);
|
||||||
|
|
||||||
assertThat(mController.getAvailabilityStatus())
|
assertThat(mController.getAvailabilityStatus())
|
||||||
.isEqualTo(BasePreferenceController.AVAILABLE);
|
.isEqualTo(BasePreferenceController.AVAILABLE);
|
||||||
@@ -153,12 +156,31 @@ public class AppInstallerInfoPreferenceControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_isMainlineModule_shouldReturnDisabled()
|
public void getAvailabilityStatus_isMainlineModule_shouldReturnDisabled()
|
||||||
throws PackageManager.NameNotFoundException {
|
throws PackageManager.NameNotFoundException {
|
||||||
|
final String packageName = "Package";
|
||||||
when(mUserManager.isManagedProfile()).thenReturn(false);
|
when(mUserManager.isManagedProfile()).thenReturn(false);
|
||||||
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label");
|
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label");
|
||||||
mController.setPackageName("Package");
|
mController.setPackageName(packageName);
|
||||||
when(mPackageManager.getModuleInfo("Package", 0 /* flags */)).thenReturn(new ModuleInfo());
|
mockMainlineModule(packageName, true /* isMainlineModule */);
|
||||||
|
|
||||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(
|
assertThat(mController.getAvailabilityStatus()).isEqualTo(
|
||||||
BasePreferenceController.DISABLED_FOR_USER);
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user