Merge "Add method to disable "disable" button in installed app UI" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-06-01 20:24:05 +00:00
committed by Android (Google) Code Review
6 changed files with 133 additions and 35 deletions

View File

@@ -42,6 +42,7 @@ import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -62,6 +63,7 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment
protected EnforcedAdmin mAppsControlDisallowedAdmin; protected EnforcedAdmin mAppsControlDisallowedAdmin;
protected boolean mAppsControlDisallowedBySystem; protected boolean mAppsControlDisallowedBySystem;
protected ApplicationFeatureProvider mApplicationFeatureProvider;
protected ApplicationsState mState; protected ApplicationsState mState;
protected ApplicationsState.Session mSession; protected ApplicationsState.Session mSession;
protected ApplicationsState.AppEntry mAppEntry; protected ApplicationsState.AppEntry mAppEntry;
@@ -84,13 +86,14 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
mFinishing = false; mFinishing = false;
final Activity activity = getActivity();
mState = ApplicationsState.getInstance(getActivity().getApplication()); mApplicationFeatureProvider = FeatureFactory.getFactory(activity)
.getApplicationFeatureProvider(activity);
mState = ApplicationsState.getInstance(activity.getApplication());
mSession = mState.newSession(this); mSession = mState.newSession(this);
Context context = getActivity(); mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mPm = activity.getPackageManager();
mPm = context.getPackageManager();
IBinder b = ServiceManager.getService(Context.USB_SERVICE); IBinder b = ServiceManager.getService(Context.USB_SERVICE);
mUsbManager = IUsbManager.Stub.asInterface(b); mUsbManager = IUsbManager.Stub.asInterface(b);

View File

@@ -24,6 +24,7 @@ import android.view.View;
import com.android.settings.applications.instantapps.InstantAppButtonsController; import com.android.settings.applications.instantapps.InstantAppButtonsController;
import java.util.List; import java.util.List;
import java.util.Set;
public interface ApplicationFeatureProvider { public interface ApplicationFeatureProvider {
@@ -93,6 +94,11 @@ public interface ApplicationFeatureProvider {
*/ */
List<UserAppInfo> findPersistentPreferredActivities(@UserIdInt int userId, Intent[] intents); 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. * Callback that receives the number of packages installed on the device.
*/ */

View File

@@ -135,6 +135,11 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
return preferredActivities; return preferredActivities;
} }
@Override
public Set<String> getKeepEnabledPackages() {
return new ArraySet<>();
}
private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter private static class CurrentUserAndManagedProfilePolicyInstalledAppCounter
extends InstalledAppCounter { extends InstalledAppCounter {
private NumberOfAppsCallback mCallback; private NumberOfAppsCallback mCallback;

View File

@@ -16,8 +16,6 @@
package com.android.settings.applications; package com.android.settings.applications;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.Manifest.permission; import android.Manifest.permission;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
@@ -117,6 +115,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
/** /**
* Activity to display application information from Settings. This activity presents * Activity to display application information from Settings. This activity presents
* extended information associated with a package like code, data, total size, permissions * extended information associated with a package like code, data, total size, permissions
@@ -232,7 +232,8 @@ public class InstalledAppDetails extends AppInfoBase
} }
}; };
private boolean handleDisableable(Button button) { @VisibleForTesting
boolean handleDisableable(Button button) {
boolean disableable = false; boolean disableable = false;
// Try to prevent the user from bricking their phone // Try to prevent the user from bricking their phone
// by not allowing disabling of apps signed with the // by not allowing disabling of apps signed with the
@@ -243,7 +244,8 @@ public class InstalledAppDetails extends AppInfoBase
button.setText(R.string.disable_text); button.setText(R.string.disable_text);
} else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) { } else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
button.setText(R.string.disable_text); button.setText(R.string.disable_text);
disableable = true; disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
.contains(mAppEntry.info.packageName);
} else { } else {
button.setText(R.string.enable_text); button.setText(R.string.enable_text);
disableable = true; disableable = true;
@@ -1221,9 +1223,7 @@ public class InstalledAppDetails extends AppInfoBase
void maybeAddInstantAppButtons() { void maybeAddInstantAppButtons() {
if (AppUtils.isInstant(mPackageInfo.applicationInfo)) { if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS); LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
final Activity activity = getActivity(); mInstantAppButtonsController = mApplicationFeatureProvider
mInstantAppButtonsController = FeatureFactory.getFactory(activity)
.getApplicationFeatureProvider(activity)
.newInstantAppButtonsController(this, .newInstantAppButtonsController(this,
buttons.findViewById(R.id.instant_app_button_container), buttons.findViewById(R.id.instant_app_button_container),
id -> showDialogInner(id, 0)) id -> showDialogInner(id, 0))

View File

@@ -245,6 +245,12 @@ public final class ApplicationFeatureProviderImplTest {
.isEqualTo(expectedManagedUserActivities); .isEqualTo(expectedManagedUserActivities);
} }
@Test
public void getKeepEnabledPackages_shouldContainNothing() {
assertThat(mProvider.getKeepEnabledPackages())
.isEmpty();
}
private void setUpUsersAndInstalledApps() { private void setUpUsersAndInstalledApps() {
when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList( when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList(
new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN), new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN),

View File

@@ -16,21 +16,6 @@
package com.android.settings.applications; package com.android.settings.applications;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyDouble;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
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.AlertDialog;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
@@ -38,6 +23,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.UserManager; import android.os.UserManager;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
@@ -55,6 +41,7 @@ import com.android.settings.TestConfig;
import com.android.settings.applications.instantapps.InstantAppButtonsController; import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.Utils;
import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats; import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
@@ -68,11 +55,27 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyDouble;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
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) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -86,8 +89,6 @@ public final class InstalledAppDetailsTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext; private Context mContext;
@Mock
ApplicationFeatureProvider mApplicationFeatureProvider;
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private UserManager mUserManager; private UserManager mUserManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -106,15 +107,18 @@ public final class InstalledAppDetailsTest {
private PackageManager mPackageManager; private PackageManager mPackageManager;
@Mock @Mock
private BatteryUtils mBatteryUtils; private BatteryUtils mBatteryUtils;
private FakeFeatureFactory mFeatureFactory;
private InstalledAppDetails mAppDetail; private InstalledAppDetails mAppDetail;
private Context mShadowContext; private Context mShadowContext;
private Preference mBatteryPreference; private Preference mBatteryPreference;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mShadowContext = RuntimeEnvironment.application; mShadowContext = RuntimeEnvironment.application;
mAppDetail = spy(new InstalledAppDetails()); mAppDetail = spy(new InstalledAppDetails());
mAppDetail.mBatteryUtils = mBatteryUtils; mAppDetail.mBatteryUtils = mBatteryUtils;
@@ -346,15 +350,14 @@ public final class InstalledAppDetailsTest {
final InstalledAppDetailsWithMockInstantButtons final InstalledAppDetailsWithMockInstantButtons
fragment = new InstalledAppDetailsWithMockInstantButtons(); fragment = new InstalledAppDetailsWithMockInstantButtons();
ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo); ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
mFeatureFactory.applicationFeatureProvider);
final InstantAppButtonsController buttonsController = final InstantAppButtonsController buttonsController =
mock(InstantAppButtonsController.class); mock(InstantAppButtonsController.class);
when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController); when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
FakeFeatureFactory.setupForTest(mContext); when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
FakeFeatureFactory factory =
(FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
when(factory.applicationFeatureProvider.newInstantAppButtonsController(
any(), any(), any())).thenReturn(buttonsController); any(), any(), any())).thenReturn(buttonsController);
fragment.maybeAddInstantAppButtons(); fragment.maybeAddInstantAppButtons();
@@ -458,4 +461,79 @@ public final class InstalledAppDetailsTest {
public void isBatteryStatsAvailable_parametersNull_returnFalse() { public void isBatteryStatsAvailable_parametersNull_returnFalse() {
assertThat(mAppDetail.isBatteryStatsAvailable()).isFalse(); 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;
}
}
} }