Merge "Adding switch for Forced App Standby"

This commit is contained in:
TreeHugger Robot
2017-09-11 22:48:35 +00:00
committed by Android (Google) Code Review
4 changed files with 190 additions and 85 deletions

View File

@@ -4630,6 +4630,12 @@
<string name="background_activity_summary_off">App\'s background activity is limited when not in use</string> <string name="background_activity_summary_off">App\'s background activity is limited when not in use</string>
<!-- Summary for the background activity when it is disabled [CHAR_LIMIT=120] --> <!-- Summary for the background activity when it is disabled [CHAR_LIMIT=120] -->
<string name="background_activity_summary_disabled">App not allowed to run in background</string> <string name="background_activity_summary_disabled">App not allowed to run in background</string>
<!-- TODO: Pending UX review. Summary for the background activity when it is whitlisted [CHAR_LIMIT=120] -->
<string name="background_activity_summary_whitelisted">App can not be optimized for battery use</string>
<!-- TODO: Pending UX review. Title for the warning dialog to show to the user when limiting background activity for an app -->
<string name="background_activity_warning_dialog_title">Limit background activity?</string>
<!-- TODO: Pending UX review. Text for the warning dialog to show to the user when limiting background activity for an app -->
<string name="background_activity_warning_dialog_text">If you limit background activity for an app, it may misbehave</string>
<!-- Title for the screen usage in power use UI [CHAR_LIMIT=60] --> <!-- Title for the screen usage in power use UI [CHAR_LIMIT=60] -->
<string name="device_screen_usage">Screen usage since full charge</string> <string name="device_screen_usage">Screen usage since full charge</string>

View File

@@ -68,7 +68,8 @@ import java.util.List;
public class AdvancedPowerUsageDetail extends DashboardFragment implements public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener, ButtonActionDialogFragment.AppButtonsDialogListener,
AnomalyDialogFragment.AnomalyDialogListener, AnomalyDialogFragment.AnomalyDialogListener,
LoaderManager.LoaderCallbacks<List<Anomaly>> { LoaderManager.LoaderCallbacks<List<Anomaly>>,
BackgroundActivityPreferenceController.WarningConfirmationListener {
public static final String TAG = "AdvancedPowerUsageDetail"; public static final String TAG = "AdvancedPowerUsageDetail";
public static final String EXTRA_UID = "extra_uid"; public static final String EXTRA_UID = "extra_uid";
@@ -109,6 +110,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
@VisibleForTesting @VisibleForTesting
AnomalySummaryPreferenceController mAnomalySummaryPreferenceController; AnomalySummaryPreferenceController mAnomalySummaryPreferenceController;
private AppButtonsPreferenceController mAppButtonsPreferenceController; private AppButtonsPreferenceController mAppButtonsPreferenceController;
private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController;
private DevicePolicyManagerWrapper mDpm; private DevicePolicyManagerWrapper mDpm;
private UserManager mUserManager; private UserManager mUserManager;
@@ -319,7 +321,9 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
final int uid = bundle.getInt(EXTRA_UID, 0); final int uid = bundle.getInt(EXTRA_UID, 0);
final String packageName = bundle.getString(EXTRA_PACKAGE_NAME); final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
controllers.add(new BackgroundActivityPreferenceController(context, uid)); mBackgroundActivityPreferenceController = new BackgroundActivityPreferenceController(
context, this, uid, packageName);
controllers.add(mBackgroundActivityPreferenceController);
controllers.add(new BatteryOptimizationPreferenceController( controllers.add(new BatteryOptimizationPreferenceController(
(SettingsActivity) getActivity(), this, packageName)); (SettingsActivity) getActivity(), this, packageName));
mAppButtonsPreferenceController = new AppButtonsPreferenceController( mAppButtonsPreferenceController = new AppButtonsPreferenceController(
@@ -364,4 +368,10 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
public void onLoaderReset(Loader<List<Anomaly>> loader) { public void onLoaderReset(Loader<List<Anomaly>> loader) {
} }
@Override
public void onLimitBackgroundActivity() {
mBackgroundActivityPreferenceController.setUnchecked(
findPreference(mBackgroundActivityPreferenceController.getPreferenceKey()));
}
} }

View File

@@ -14,12 +14,17 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.app.AlertDialog;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.Dialog;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.SwitchPreference; import android.support.v14.preference.SwitchPreference;
@@ -29,6 +34,7 @@ import android.util.Log;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.enterprise.DevicePolicyManagerWrapper; import com.android.settings.enterprise.DevicePolicyManagerWrapper;
import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl; import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -45,54 +51,72 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
private final AppOpsManager mAppOpsManager; private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager; private final UserManager mUserManager;
private final String[] mPackages;
private final int mUid; private final int mUid;
@VisibleForTesting @VisibleForTesting
DevicePolicyManagerWrapper mDpm; DevicePolicyManagerWrapper mDpm;
private Fragment mFragment;
private String mTargetPackage; private String mTargetPackage;
private boolean mIsPreOApp;
private PowerWhitelistBackend mPowerWhitelistBackend;
public BackgroundActivityPreferenceController(Context context, int uid) { public BackgroundActivityPreferenceController(Context context, Fragment fragment,
int uid, String packageName) {
this(context, fragment, uid, packageName, PowerWhitelistBackend.getInstance());
}
@VisibleForTesting
BackgroundActivityPreferenceController(Context context, Fragment fragment,
int uid, String packageName, PowerWhitelistBackend backend) {
super(context); super(context);
mPowerWhitelistBackend = backend;
mPackageManager = context.getPackageManager(); mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mDpm = new DevicePolicyManagerWrapperImpl( mDpm = new DevicePolicyManagerWrapperImpl(
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)); (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE));
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mUid = uid; mUid = uid;
mPackages = mPackageManager.getPackagesForUid(mUid); mFragment = fragment;
mTargetPackage = packageName;
mIsPreOApp = isLegacyApp(packageName);
} }
@Override @Override
public void updateState(Preference preference) { public void updateState(Preference preference) {
final int mode = mAppOpsManager final int mode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage); .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
final boolean whitelisted = mPowerWhitelistBackend.isWhitelisted(mTargetPackage);
// Set checked or not before we may set it disabled // Set checked or not before we may set it disabled
if (mode != AppOpsManager.MODE_ERRORED) { if (mode != AppOpsManager.MODE_ERRORED) {
final boolean checked = mode != AppOpsManager.MODE_IGNORED; final boolean checked = whitelisted || mode != AppOpsManager.MODE_IGNORED;
((SwitchPreference) preference).setChecked(checked); ((SwitchPreference) preference).setChecked(checked);
} }
if (mode == AppOpsManager.MODE_ERRORED if (whitelisted || mode == AppOpsManager.MODE_ERRORED
|| Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) { || Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) {
preference.setEnabled(false); preference.setEnabled(false);
} else {
preference.setEnabled(true);
} }
updateSummary(preference); updateSummary(preference);
} }
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
if (mPackages == null) { return mTargetPackage != null;
return false;
}
for (final String packageName : mPackages) {
if (isLegacyApp(packageName)) {
mTargetPackage = packageName;
return true;
}
} }
return false; /**
* Called from the warning dialog, if the user decides to go ahead and disable background
* activity for this package
*/
public void setUnchecked(Preference preference) {
if (mIsPreOApp) {
mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_IGNORED);
}
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_IGNORED);
((SwitchPreference) preference).setChecked(false);
updateSummary(preference);
} }
@Override @Override
@@ -102,19 +126,23 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
@Override @Override
public boolean onPreferenceChange(Preference preference, Object newValue) { public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean switchOn = (Boolean) newValue; final boolean switchOn = (Boolean) newValue;
if (!switchOn) {
final WarningDialogFragment dialogFragment = new WarningDialogFragment();
dialogFragment.setTargetFragment(mFragment, 0);
dialogFragment.show(mFragment.getFragmentManager(), TAG);
return false;
}
if (mIsPreOApp) {
mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage, mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
switchOn ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); AppOpsManager.MODE_ALLOWED);
}
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_ALLOWED);
updateSummary(preference); updateSummary(preference);
return true; return true;
} }
@VisibleForTesting
String getTargetPackage() {
return mTargetPackage;
}
@VisibleForTesting @VisibleForTesting
boolean isLegacyApp(final String packageName) { boolean isLegacyApp(final String packageName) {
try { try {
@@ -131,8 +159,12 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
@VisibleForTesting @VisibleForTesting
void updateSummary(Preference preference) { void updateSummary(Preference preference) {
if (mPowerWhitelistBackend.isWhitelisted(mTargetPackage)) {
preference.setSummary(R.string.background_activity_summary_whitelisted);
return;
}
final int mode = mAppOpsManager final int mode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage); .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
if (mode == AppOpsManager.MODE_ERRORED) { if (mode == AppOpsManager.MODE_ERRORED) {
preference.setSummary(R.string.background_activity_summary_disabled); preference.setSummary(R.string.background_activity_summary_disabled);
@@ -142,4 +174,37 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
: R.string.background_activity_summary_off); : R.string.background_activity_summary_off);
} }
} }
interface WarningConfirmationListener {
void onLimitBackgroundActivity();
}
/**
* Warning dialog to show to the user as turning off background activity can lead to
* apps misbehaving as their background task scheduling guarantees will no longer be honored.
*/
public static class WarningDialogFragment extends InstrumentedDialogFragment {
@Override
public int getMetricsCategory() {
// TODO (b/65494831): add metric id
return 0;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final WarningConfirmationListener listener =
(WarningConfirmationListener) getTargetFragment();
return new AlertDialog.Builder(getContext())
.setTitle(R.string.background_activity_warning_dialog_title)
.setMessage(R.string.background_activity_warning_dialog_text)
.setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onLimitBackgroundActivity();
}
})
.setNegativeButton(R.string.dlg_cancel, null)
.create();
}
}
} }

View File

@@ -16,14 +16,25 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.AlertDialog;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.os.UserManager; import android.os.UserManager;
import android.support.v14.preference.SwitchPreference; import android.support.v14.preference.SwitchPreference;
import android.widget.Button;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
@@ -38,22 +49,17 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowAlertDialog;
import static com.google.common.truth.Truth.assertThat; import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.FragmentTestUtil;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BackgroundActivityPreferenceControllerTest { public class BackgroundActivityPreferenceControllerTest {
private static final int UID_NORMAL = 1234; private static final int UID_LOW_SDK = 1234;
private static final int UID_SPECIAL = 2345; private static final int UID_HIGH_SDK = 3456;
private static final String HIGH_SDK_PACKAGE = "com.android.package.high"; private static final String HIGH_SDK_PACKAGE = "com.android.package.high";
private static final String LOW_SDK_PACKAGE = "com.android.package.low"; private static final String LOW_SDK_PACKAGE = "com.android.package.low";
private static final String[] PACKAGES_NORMAL = {LOW_SDK_PACKAGE};
private static final String[] PACKAGES_SPECIAL = {HIGH_SDK_PACKAGE, LOW_SDK_PACKAGE};
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext; private Context mContext;
@@ -71,6 +77,10 @@ public class BackgroundActivityPreferenceControllerTest {
private DevicePolicyManager mDevicePolicyManager; private DevicePolicyManager mDevicePolicyManager;
@Mock @Mock
private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper; private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper;
@Mock
private AdvancedPowerUsageDetail mFragment;
@Mock
private PowerWhitelistBackend mPowerWhitelistBackend;
private BackgroundActivityPreferenceController mController; private BackgroundActivityPreferenceController mController;
private SwitchPreference mPreference; private SwitchPreference mPreference;
private Context mShadowContext; private Context mShadowContext;
@@ -85,19 +95,19 @@ public class BackgroundActivityPreferenceControllerTest {
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
mDevicePolicyManager); mDevicePolicyManager);
when(mPackageManager.getPackagesForUid(UID_NORMAL)).thenReturn(PACKAGES_NORMAL);
when(mPackageManager.getPackagesForUid(UID_SPECIAL)).thenReturn(PACKAGES_SPECIAL);
when(mPackageManager.getApplicationInfo(HIGH_SDK_PACKAGE, PackageManager.GET_META_DATA)) when(mPackageManager.getApplicationInfo(HIGH_SDK_PACKAGE, PackageManager.GET_META_DATA))
.thenReturn(mHighApplicationInfo); .thenReturn(mHighApplicationInfo);
when(mPackageManager.getApplicationInfo(LOW_SDK_PACKAGE, PackageManager.GET_META_DATA)) when(mPackageManager.getApplicationInfo(LOW_SDK_PACKAGE, PackageManager.GET_META_DATA))
.thenReturn(mLowApplicationInfo); .thenReturn(mLowApplicationInfo);
when(mPowerWhitelistBackend.isWhitelisted(LOW_SDK_PACKAGE)).thenReturn(false);
mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O; mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L; mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;
mPreference = new SwitchPreference(mShadowContext); mPreference = new SwitchPreference(mShadowContext);
mController = spy(new BackgroundActivityPreferenceController(mContext, UID_NORMAL)); mController = spy(new BackgroundActivityPreferenceController(
mController.isAvailable(); mContext, mFragment, UID_LOW_SDK, LOW_SDK_PACKAGE, mPowerWhitelistBackend));
mController.mDpm = mDevicePolicyManagerWrapper; mController.mDpm = mDevicePolicyManagerWrapper;
} }
@@ -105,49 +115,66 @@ public class BackgroundActivityPreferenceControllerTest {
public void testOnPreferenceChange_TurnOnCheck_MethodInvoked() { public void testOnPreferenceChange_TurnOnCheck_MethodInvoked() {
mController.onPreferenceChange(mPreference, true); mController.onPreferenceChange(mPreference, true);
verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_LOW_SDK,
mController.getTargetPackage(), AppOpsManager.MODE_ALLOWED); LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
verify(mController).updateSummary(mPreference); verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
assertThat(mPreference.getSummary())
.isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
} }
@Test @Test
public void testOnPreferenceChange_TurnOffCheck_MethodInvoked() { public void testOnPreferenceChange_TurnOnCheckHighSDK_MethodInvoked() {
mController.onPreferenceChange(mPreference, false); mController = new BackgroundActivityPreferenceController(mContext, mFragment, UID_HIGH_SDK,
HIGH_SDK_PACKAGE, mPowerWhitelistBackend);
verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, mController.onPreferenceChange(mPreference, true);
mController.getTargetPackage(), AppOpsManager.MODE_IGNORED); verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_HIGH_SDK,
verify(mController).updateSummary(mPreference); HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_HIGH_SDK,
HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
assertThat(mPreference.getSummary())
.isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
} }
@Test @Test
public void testUpdateState_CheckOn_SetCheckedTrue() { public void testUpdateState_CheckOn_SetCheckedTrue() {
when(mAppOpsManager when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE)) LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_ALLOWED);
.thenReturn(AppOpsManager.MODE_DEFAULT);
mController.updateState(mPreference); mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue(); assertThat(mPreference.isChecked()).isTrue();
assertThat(mPreference.isEnabled()).isTrue();
verify(mController).updateSummary(mPreference); verify(mController).updateSummary(mPreference);
} }
@Test @Test
public void testUpdateState_CheckOff_SetCheckedFalse() { public void testUpdateState_CheckOff_SetCheckedFalse() {
when(mAppOpsManager when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE)) LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
.thenReturn(AppOpsManager.MODE_IGNORED);
mController.updateState(mPreference); mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse(); assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.isEnabled()).isTrue();
verify(mController).updateSummary(mPreference); verify(mController).updateSummary(mPreference);
} }
@Test
public void testUpdateState_whitelisted() {
when(mPowerWhitelistBackend.isWhitelisted(LOW_SDK_PACKAGE)).thenReturn(true);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getSummary()).isEqualTo(
mShadowContext.getText(R.string.background_activity_summary_whitelisted));
}
@Test @Test
public void testUpdateSummary_modeError_showSummaryDisabled() { public void testUpdateSummary_modeError_showSummaryDisabled() {
when(mAppOpsManager when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE)) LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_ERRORED);
.thenReturn(AppOpsManager.MODE_ERRORED);
final CharSequence expectedSummary = mShadowContext.getText( final CharSequence expectedSummary = mShadowContext.getText(
R.string.background_activity_summary_disabled); R.string.background_activity_summary_disabled);
mController.updateSummary(mPreference); mController.updateSummary(mPreference);
@@ -157,9 +184,8 @@ public class BackgroundActivityPreferenceControllerTest {
@Test @Test
public void testUpdateSummary_modeDefault_showSummaryOn() { public void testUpdateSummary_modeDefault_showSummaryOn() {
when(mAppOpsManager when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE)) LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_DEFAULT);
.thenReturn(AppOpsManager.MODE_DEFAULT);
final CharSequence expectedSummary = mShadowContext.getText( final CharSequence expectedSummary = mShadowContext.getText(
R.string.background_activity_summary_on); R.string.background_activity_summary_on);
@@ -170,9 +196,8 @@ public class BackgroundActivityPreferenceControllerTest {
@Test @Test
public void testUpdateSummary_modeIgnored_showSummaryOff() { public void testUpdateSummary_modeIgnored_showSummaryOff() {
when(mAppOpsManager when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE)) LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
.thenReturn(AppOpsManager.MODE_IGNORED);
final CharSequence expectedSummary = mShadowContext.getText( final CharSequence expectedSummary = mShadowContext.getText(
R.string.background_activity_summary_off); R.string.background_activity_summary_off);
@@ -182,31 +207,30 @@ public class BackgroundActivityPreferenceControllerTest {
} }
@Test @Test
public void testIsPackageAvailable_SdkLowerThanO_ReturnTrue() { public void testIsLegacyApp_SdkLowerThanO_ReturnTrue() {
assertThat(mController.isLegacyApp(LOW_SDK_PACKAGE)).isTrue(); assertThat(mController.isLegacyApp(LOW_SDK_PACKAGE)).isTrue();
} }
@Test @Test
public void testIsPackageAvailable_SdkLargerOrEqualThanO_ReturnFalse() { public void testIsLegacyApp_SdkLargerOrEqualThanO_ReturnFalse() {
assertThat(mController.isLegacyApp(HIGH_SDK_PACKAGE)).isFalse(); assertThat(mController.isLegacyApp(HIGH_SDK_PACKAGE)).isFalse();
} }
@Test @Test
public void testMultiplePackages_ReturnStatusForTargetPackage() { public void testIsAvailable_ReturnTrue() {
mController = new BackgroundActivityPreferenceController(mContext, UID_SPECIAL); assertThat(mController.isAvailable()).isTrue();
mController.mDpm = mDevicePolicyManagerWrapper; }
when(mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_SPECIAL, LOW_SDK_PACKAGE))
.thenReturn(AppOpsManager.MODE_ALLOWED);
when(mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_SPECIAL, HIGH_SDK_PACKAGE))
.thenReturn(AppOpsManager.MODE_IGNORED);
final boolean available = mController.isAvailable(); @Test
mController.updateState(mPreference); public void testWarningDialog() {
BackgroundActivityPreferenceController.WarningDialogFragment dialogFragment =
assertThat(available).isTrue(); new BackgroundActivityPreferenceController.WarningDialogFragment();
// Should get status from LOW_SDK_PACKAGE dialogFragment.setTargetFragment(mFragment, 0);
assertThat(mPreference.isChecked()).isTrue(); FragmentTestUtil.startFragment(dialogFragment);
final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
ShadowAlertDialog shadowDialog = shadowOf(dialog);
final Button okButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
shadowDialog.clickOn(okButton.getId());
verify(mFragment).onLimitBackgroundActivity();
} }
} }