Add method to disable "disable" button in installed app UI
OEMs can now force grey out the "disable" button for important apps on device. Change-Id: Ic075a07ad12592bd60238c7b1c9ab84932c8db3c Fix: 38250742 Test: make RunSettingsRoboTests
This commit is contained in:
@@ -42,6 +42,7 @@ import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
@@ -62,6 +63,7 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment
|
||||
protected EnforcedAdmin mAppsControlDisallowedAdmin;
|
||||
protected boolean mAppsControlDisallowedBySystem;
|
||||
|
||||
protected ApplicationFeatureProvider mApplicationFeatureProvider;
|
||||
protected ApplicationsState mState;
|
||||
protected ApplicationsState.Session mSession;
|
||||
protected ApplicationsState.AppEntry mAppEntry;
|
||||
@@ -84,13 +86,14 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mFinishing = false;
|
||||
|
||||
mState = ApplicationsState.getInstance(getActivity().getApplication());
|
||||
final Activity activity = getActivity();
|
||||
mApplicationFeatureProvider = FeatureFactory.getFactory(activity)
|
||||
.getApplicationFeatureProvider(activity);
|
||||
mState = ApplicationsState.getInstance(activity.getApplication());
|
||||
mSession = mState.newSession(this);
|
||||
Context context = getActivity();
|
||||
mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
mPm = context.getPackageManager();
|
||||
mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
|
||||
mPm = activity.getPackageManager();
|
||||
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
|
||||
mUsbManager = IUsbManager.Stub.asInterface(b);
|
||||
|
||||
|
@@ -24,6 +24,7 @@ import android.view.View;
|
||||
import com.android.settings.applications.instantapps.InstantAppButtonsController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ApplicationFeatureProvider {
|
||||
|
||||
@@ -86,6 +87,11 @@ public interface ApplicationFeatureProvider {
|
||||
*/
|
||||
List<UserAppInfo> findPersistentPreferredActivities(@UserIdInt int userId, Intent[] intents);
|
||||
|
||||
/**
|
||||
* Returns a list of package names that should be kept enabled.
|
||||
*/
|
||||
Set<String> getKeepEnabledPackages();
|
||||
|
||||
/**
|
||||
* Callback that receives the number of packages installed on the device.
|
||||
*/
|
||||
|
@@ -129,6 +129,11 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
|
||||
return preferredActivities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeepEnabledPackages() {
|
||||
return new ArraySet<>();
|
||||
}
|
||||
|
||||
private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter
|
||||
extends InstalledAppCounter {
|
||||
private NumberOfAppsCallback mCallback;
|
||||
|
@@ -91,7 +91,6 @@ import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.notification.AppNotificationSettings;
|
||||
import com.android.settings.notification.NotificationBackend;
|
||||
import com.android.settings.notification.NotificationBackend.AppRow;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.AppItem;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
@@ -228,7 +227,8 @@ public class InstalledAppDetails extends AppInfoBase
|
||||
}
|
||||
};
|
||||
|
||||
private boolean handleDisableable(Button button) {
|
||||
@VisibleForTesting
|
||||
boolean handleDisableable(Button button) {
|
||||
boolean disableable = false;
|
||||
// Try to prevent the user from bricking their phone
|
||||
// by not allowing disabling of apps signed with the
|
||||
@@ -239,7 +239,8 @@ public class InstalledAppDetails extends AppInfoBase
|
||||
button.setText(R.string.disable_text);
|
||||
} else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
|
||||
button.setText(R.string.disable_text);
|
||||
disableable = true;
|
||||
disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
|
||||
.contains(mAppEntry.info.packageName);
|
||||
} else {
|
||||
button.setText(R.string.enable_text);
|
||||
disableable = true;
|
||||
@@ -1214,9 +1215,7 @@ public class InstalledAppDetails extends AppInfoBase
|
||||
void maybeAddInstantAppButtons() {
|
||||
if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
|
||||
LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
|
||||
final Activity activity = getActivity();
|
||||
mInstantAppButtonsController = FeatureFactory.getFactory(activity)
|
||||
.getApplicationFeatureProvider(activity)
|
||||
mInstantAppButtonsController = mApplicationFeatureProvider
|
||||
.newInstantAppButtonsController(this,
|
||||
buttons.findViewById(R.id.instant_app_button_container),
|
||||
id -> showDialogInner(id, 0))
|
||||
|
@@ -245,6 +245,12 @@ public final class ApplicationFeatureProviderImplTest {
|
||||
.isEqualTo(expectedManagedUserActivities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getKeepEnabledPackages_shouldContainNothing() {
|
||||
assertThat(mProvider.getKeepEnabledPackages())
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
private void setUpUsersAndInstalledApps() {
|
||||
when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
|
||||
new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),
|
||||
|
@@ -17,19 +17,6 @@
|
||||
package com.android.settings.applications;
|
||||
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Matchers.anyDouble;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
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.app.AlertDialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -38,6 +25,7 @@ import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.UserManager;
|
||||
import android.support.v7.preference.Preference;
|
||||
@@ -56,6 +44,7 @@ import com.android.settings.applications.instantapps.InstantAppButtonsController
|
||||
import com.android.settings.applications.instantapps.InstantAppButtonsController.ShowDialogDelegate;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
|
||||
@@ -69,11 +58,26 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Matchers.anyDouble;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
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;
|
||||
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||
@@ -87,8 +91,6 @@ public final class InstalledAppDetailsTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@Mock
|
||||
ApplicationFeatureProvider mApplicationFeatureProvider;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private UserManager mUserManager;
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
@@ -107,15 +109,17 @@ public final class InstalledAppDetailsTest {
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private BatteryUtils mBatteryUtils;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
|
||||
private InstalledAppDetails mAppDetail;
|
||||
private Context mShadowContext;
|
||||
private Preference mBatteryPreference;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest(mContext);
|
||||
mShadowContext = RuntimeEnvironment.application;
|
||||
mAppDetail = spy(new InstalledAppDetails());
|
||||
mAppDetail.mBatteryUtils = mBatteryUtils;
|
||||
@@ -347,16 +351,14 @@ public final class InstalledAppDetailsTest {
|
||||
final InstalledAppDetailsWithMockInstantButtons
|
||||
fragment = new InstalledAppDetailsWithMockInstantButtons();
|
||||
ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
|
||||
ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
|
||||
mFeatureFactory.applicationFeatureProvider);
|
||||
|
||||
final InstantAppButtonsController buttonsController =
|
||||
mock(InstantAppButtonsController.class);
|
||||
when(buttonsController.setPackageName(nullable(String.class)))
|
||||
.thenReturn(buttonsController);
|
||||
|
||||
FakeFeatureFactory.setupForTest(mContext);
|
||||
FakeFeatureFactory factory =
|
||||
(FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||
when(factory.applicationFeatureProvider.newInstantAppButtonsController(
|
||||
when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
|
||||
nullable(Fragment.class), nullable(View.class), nullable(ShowDialogDelegate.class)))
|
||||
.thenReturn(buttonsController);
|
||||
|
||||
@@ -461,4 +463,79 @@ public final class InstalledAppDetailsTest {
|
||||
public void isBatteryStatsAvailable_parametersNull_returnFalse() {
|
||||
assertThat(mAppDetail.isBatteryStatsAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleDisableable_appIsHomeApp_buttonShouldNotWork() {
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = "pkg";
|
||||
info.enabled = true;
|
||||
final AppEntry appEntry = mock(AppEntry.class);
|
||||
appEntry.info = info;
|
||||
final HashSet<String> homePackages = new HashSet<>();
|
||||
homePackages.add(info.packageName);
|
||||
|
||||
ReflectionHelpers.setField(mAppDetail, "mHomePackages", homePackages);
|
||||
ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
|
||||
final Button button = mock(Button.class);
|
||||
|
||||
assertThat(mAppDetail.handleDisableable(button)).isFalse();
|
||||
verify(button).setText(R.string.disable_text);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowUtils.class)
|
||||
public void handleDisableable_appIsEnabled_buttonShouldWork() {
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = "pkg";
|
||||
info.enabled = true;
|
||||
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
|
||||
final AppEntry appEntry = mock(AppEntry.class);
|
||||
appEntry.info = info;
|
||||
when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
|
||||
new HashSet<>());
|
||||
|
||||
ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
|
||||
mFeatureFactory.applicationFeatureProvider);
|
||||
ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
|
||||
final Button button = mock(Button.class);
|
||||
|
||||
assertThat(mAppDetail.handleDisableable(button)).isTrue();
|
||||
verify(button).setText(R.string.disable_text);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowUtils.class)
|
||||
public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() {
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
info.packageName = "pkg";
|
||||
info.enabled = true;
|
||||
info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||
|
||||
final AppEntry appEntry = mock(AppEntry.class);
|
||||
appEntry.info = info;
|
||||
|
||||
final HashSet<String> packages = new HashSet<>();
|
||||
packages.add(info.packageName);
|
||||
when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
|
||||
packages);
|
||||
|
||||
ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
|
||||
mFeatureFactory.applicationFeatureProvider);
|
||||
ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
|
||||
|
||||
final Button button = mock(Button.class);
|
||||
|
||||
assertThat(mAppDetail.handleDisableable(button)).isFalse();
|
||||
verify(button).setText(R.string.disable_text);
|
||||
}
|
||||
|
||||
@Implements(Utils.class)
|
||||
public static class ShadowUtils {
|
||||
@Implementation
|
||||
public static boolean isSystemPackage(Resources resources, PackageManager pm,
|
||||
PackageInfo pkg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user