diff --git a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java index 9cb5a3f851a..708f8b7004d 100644 --- a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java +++ b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java @@ -38,6 +38,7 @@ import android.util.Log; import androidx.appcompat.app.AlertDialog; import com.android.settings.R; +import com.android.settings.fuelgauge.BatteryOptimizeUtils; import java.util.Arrays; import java.util.List; @@ -152,6 +153,7 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener, } catch (RemoteException e) { } mAom.resetAllModes(); + BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom); final int[] restrictedUids = mNpm.getUidsWithPolicy( POLICY_REJECT_METERED_BACKGROUND); final int currentUserId = ActivityManager.getCurrentUser(); diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java index f5e21ddc1b2..9860240b289 100644 --- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java +++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java @@ -24,16 +24,13 @@ import android.app.backup.BackupHelper; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.content.pm.UserInfo; import android.os.Build; import android.os.IDeviceIdleController; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; -import android.os.UserManager; +import android.util.ArraySet; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -53,22 +50,13 @@ public final class BatteryBackupHelper implements BackupHelper { private static final String DEVICE_IDLE_SERVICE = "deviceidle"; private static final boolean DEBUG = Build.TYPE.equals("userdebug"); - // Only the owner can see all apps. - private static final int RETRIEVE_FLAG_ADMIN = - PackageManager.MATCH_ANY_USER | - PackageManager.MATCH_DISABLED_COMPONENTS | - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; - private static final int RETRIEVE_FLAG = - PackageManager.MATCH_DISABLED_COMPONENTS | - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; - static final String DELIMITER = ","; static final String DELIMITER_MODE = ":"; static final String KEY_FULL_POWER_LIST = "full_power_list"; static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list"; @VisibleForTesting - List mTestApplicationInfoList = null; + ArraySet mTestApplicationInfoList = null; @VisibleForTesting PowerAllowlistBackend mPowerAllowlistBackend; @@ -146,7 +134,7 @@ public final class BatteryBackupHelper implements BackupHelper { @VisibleForTesting void backupOptimizationMode(BackupDataOutput data, List allowlistedApps) { final long timestamp = System.currentTimeMillis(); - final List applications = getInstalledApplications(); + final ArraySet applications = getInstalledApplications(); if (applications == null || applications.isEmpty()) { Log.w(TAG, "no data found in the getInstalledApplications()"); return; @@ -269,36 +257,11 @@ public final class BatteryBackupHelper implements BackupHelper { || powerAllowlistBackend.isDefaultActiveApp(packageName); } - private List getInstalledApplications() { + private ArraySet getInstalledApplications() { if (mTestApplicationInfoList != null) { return mTestApplicationInfoList; } - final List applications = new ArrayList<>(); - final UserManager um = mContext.getSystemService(UserManager.class); - for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) { - try { - @SuppressWarnings("unchecked") - final ParceledListSlice infoList = - getIPackageManager().getInstalledApplications( - userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG, - userInfo.id); - if (infoList != null) { - applications.addAll(infoList.getList()); - } - } catch (Exception e) { - Log.e(TAG, "getInstalledApplications() is failed", e); - return null; - } - } - // Removes the application which is disabled by the system. - for (int index = applications.size() - 1; index >= 0; index--) { - final ApplicationInfo info = applications.get(index); - if (info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER - && !info.enabled) { - applications.remove(index); - } - } - return applications; + return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager()); } private void debugLog(String debugContent) { diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java index 9306a34df67..dbfacc6907c 100644 --- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java @@ -19,7 +19,15 @@ package com.android.settings.fuelgauge; import android.annotation.IntDef; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; import android.os.AsyncTask; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.ArraySet; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -43,6 +51,15 @@ public class BatteryOptimizeUtils { private final String mPackageName; private final int mUid; + // If current user is admin, match apps from all users. Otherwise, only match the currect user. + private static final int RETRIEVE_FLAG_ADMIN = + PackageManager.MATCH_ANY_USER + | PackageManager.MATCH_DISABLED_COMPONENTS + | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; + private static final int RETRIEVE_FLAG = + PackageManager.MATCH_DISABLED_COMPONENTS + | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; + // Optimization modes. static final int MODE_UNKNOWN = 0; static final int MODE_RESTRICTED = 1; @@ -90,28 +107,20 @@ public class BatteryOptimizeUtils { return getAppOptimizationMode(mMode, mAllowListed); } + /** Resets optimization mode for all applications. */ + public static void resetAppOptimizationMode( + Context context, IPackageManager ipm, AppOpsManager aom) { + resetAppOptimizationMode(context, ipm, aom, + PowerAllowlistBackend.getInstance(context), BatteryUtils.getInstance(context)); + } + /** Sets the {@link OptimizationMode} for associated app. */ public void setAppUsageState(@OptimizationMode int mode) { if (getAppOptimizationMode(mMode, mAllowListed) == mode) { Log.w(TAG, "set the same optimization mode for: " + mPackageName); return; } - - AsyncTask.execute(() -> { - switch (mode) { - case MODE_RESTRICTED: - setAppOptimizationMode(AppOpsManager.MODE_IGNORED, /* allowListed */ false); - break; - case MODE_UNRESTRICTED: - setAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ true); - break; - case MODE_OPTIMIZED: - setAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false); - break; - default: - Log.d(TAG, "set unknown app optimization mode."); - } - }); + setAppUsageStateInternal(mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend); } /** @@ -126,25 +135,111 @@ public class BatteryOptimizeUtils { */ public boolean isSystemOrDefaultApp() { mPowerAllowListBackend.refreshList(); + return isSystemOrDefaultApp(mPowerAllowListBackend, mPackageName); + } - return mPowerAllowListBackend.isSysAllowlisted(mPackageName) - || mPowerAllowListBackend.isDefaultActiveApp(mPackageName); + /** + * Gets the list of installed applications. + */ + public static ArraySet getInstalledApplications( + Context context, IPackageManager ipm) { + final ArraySet applications = new ArraySet<>(); + final UserManager um = context.getSystemService(UserManager.class); + for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) { + try { + @SuppressWarnings("unchecked") + final ParceledListSlice infoList = ipm.getInstalledApplications( + userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG, + userInfo.id); + if (infoList != null) { + applications.addAll(infoList.getList()); + } + } catch (Exception e) { + Log.e(TAG, "getInstalledApplications() is failed", e); + return null; + } + } + // Removes the application which is disabled by the system. + applications.removeIf( + info -> info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER + && !info.enabled); + return applications; + } + + @VisibleForTesting + static void resetAppOptimizationMode( + Context context, IPackageManager ipm, AppOpsManager aom, + PowerAllowlistBackend allowlistBackend, BatteryUtils batteryUtils) { + final ArraySet applications = getInstalledApplications(context, ipm); + if (applications == null || applications.isEmpty()) { + Log.w(TAG, "no data found in the getInstalledApplications()"); + return; + } + + allowlistBackend.refreshList(); + // Resets optimization mode for each application. + for (ApplicationInfo info : applications) { + final int mode = aom.checkOpNoThrow( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName); + @OptimizationMode + final int optimizationMode = getAppOptimizationMode( + mode, allowlistBackend.isAllowlisted(info.packageName)); + // Ignores default optimized/unknown state or system/default apps. + if (optimizationMode == MODE_OPTIMIZED + || optimizationMode == MODE_UNKNOWN + || isSystemOrDefaultApp(allowlistBackend, info.packageName)) { + continue; + } + + // Resets to the default mode: MODE_OPTIMIZED. + setAppUsageStateInternal(MODE_OPTIMIZED, info.uid, info.packageName, batteryUtils, + allowlistBackend); + } } String getPackageName() { return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName; } - private void setAppOptimizationMode(int appStandbyMode, boolean allowListed) { + private static boolean isSystemOrDefaultApp( + PowerAllowlistBackend powerAllowlistBackend, String packageName) { + return powerAllowlistBackend.isSysAllowlisted(packageName) + || powerAllowlistBackend.isDefaultActiveApp(packageName); + } + + private static void setAppUsageStateInternal( + @OptimizationMode int mode, int uid, String packageName, BatteryUtils batteryUtils, + PowerAllowlistBackend powerAllowlistBackend) { + if (mode == MODE_UNKNOWN) { + Log.d(TAG, "set unknown app optimization mode."); + return; + } + + // MODE_RESTRICTED = AppOpsManager.MODE_IGNORED + !allowListed + // MODE_UNRESTRICTED = AppOpsManager.MODE_ALLOWED + allowListed + // MODE_OPTIMIZED = AppOpsManager.MODE_ALLOWED + !allowListed + final int appOpsManagerMode = + mode == MODE_RESTRICTED ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED; + final boolean allowListed = mode == MODE_UNRESTRICTED; + + AsyncTask.execute(() -> { + setAppOptimizationModeInternal(appOpsManagerMode, allowListed, uid, packageName, + batteryUtils, powerAllowlistBackend); + }); + } + + private static void setAppOptimizationModeInternal( + int appStandbyMode, boolean allowListed, int uid, String packageName, + BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend) { try { - mBatteryUtils.setForceAppStandby(mUid, mPackageName, appStandbyMode); + batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode); if (allowListed) { - mPowerAllowListBackend.addApp(mPackageName); + powerAllowlistBackend.addApp(packageName); } else { - mPowerAllowListBackend.removeApp(mPackageName); + powerAllowlistBackend.removeApp(packageName); } } catch (Exception e) { - Log.e(TAG, "set OPTIMIZED failed for " + mPackageName, e); + Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e); } } @@ -154,8 +249,6 @@ public class BatteryOptimizeUtils { mMode = mAppOpsManager .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName); Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d", - mPackageName, - mAllowListed, - mMode)); + mPackageName, mAllowListed, mMode)); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java index ca1797ac9e9..14bbeea7187 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -48,6 +49,7 @@ import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.ArraySet; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; @@ -193,7 +195,7 @@ public final class BatteryBackupHelperTest { doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt()); doThrow(new RuntimeException()) .when(mIPackageManager) - .getInstalledApplications(anyInt(), anyInt()); + .getInstalledApplications(anyLong(), anyInt()); mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, null); @@ -369,7 +371,7 @@ public final class BatteryBackupHelperTest { doReturn(new ParceledListSlice( Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3))) .when(mIPackageManager) - .getInstalledApplications(anyInt(), anyInt()); + .getInstalledApplications(anyLong(), anyInt()); // Sets the AppOpsManager for checkOpNoThrow() method. doReturn(AppOpsManager.MODE_ALLOWED) .when(mAppOpsManager) @@ -384,7 +386,7 @@ public final class BatteryBackupHelperTest { applicationInfo2.uid, applicationInfo2.packageName); mBatteryBackupHelper.mTestApplicationInfoList = - Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3); + new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3)); } @Implements(UserHandle.class) diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java index c154f426b30..b223d0bc755 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java @@ -22,26 +22,43 @@ import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRIC import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; +import android.os.UserManager; +import android.util.ArraySet; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.util.Arrays; import java.util.concurrent.TimeUnit; @RunWith(RobolectricTestRunner.class) @@ -50,9 +67,11 @@ public class BatteryOptimizeUtilsTest { private static final int UID = 12345; private static final String PACKAGE_NAME = "com.android.app"; - @Mock BatteryUtils mMockBatteryUtils; - @Mock AppOpsManager mMockAppOpsManager; - @Mock PowerAllowlistBackend mMockBackend; + @Mock private BatteryUtils mMockBatteryUtils; + @Mock private AppOpsManager mMockAppOpsManager; + @Mock private PowerAllowlistBackend mMockBackend; + @Mock private IPackageManager mMockIPackageManager; + @Mock private UserManager mMockUserManager; private Context mContext; private BatteryOptimizeUtils mBatteryOptimizeUtils; @@ -68,6 +87,7 @@ public class BatteryOptimizeUtilsTest { // Sets the default mode as MODE_RESTRICTED. mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_IGNORED; mBatteryOptimizeUtils.mAllowListed = false; + doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class); } @Test @@ -135,9 +155,7 @@ public class BatteryOptimizeUtilsTest { mBatteryOptimizeUtils.setAppUsageState(MODE_RESTRICTED); TimeUnit.SECONDS.sleep(1); - verify(mMockBatteryUtils).setForceAppStandby(UID, - PACKAGE_NAME, AppOpsManager.MODE_IGNORED); - verify(mMockBackend).removeApp(PACKAGE_NAME); + verifySetAppOptimizationMode(AppOpsManager.MODE_IGNORED, /* allowListed */ false); } @Test @@ -145,9 +163,7 @@ public class BatteryOptimizeUtilsTest { mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED); TimeUnit.SECONDS.sleep(1); - verify(mMockBatteryUtils).setForceAppStandby(UID, - PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); - verify(mMockBackend).addApp(PACKAGE_NAME); + verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ true); } @Test @@ -155,9 +171,7 @@ public class BatteryOptimizeUtilsTest { mBatteryOptimizeUtils.setAppUsageState(MODE_OPTIMIZED); TimeUnit.SECONDS.sleep(1); - verify(mMockBatteryUtils).setForceAppStandby(UID, - PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); - verify(mMockBackend).removeApp(PACKAGE_NAME); + verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false); } @Test @@ -172,4 +186,148 @@ public class BatteryOptimizeUtilsTest { verifyZeroInteractions(mMockBackend); verifyZeroInteractions(mMockBatteryUtils); } + + @Test + public void testGetInstalledApplications_returnEmptyArray() { + assertTrue(BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager) + .isEmpty()); + } + + @Test + public void testGetInstalledApplications_returnNull() throws Exception { + final UserInfo userInfo = + new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0); + doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt()); + doThrow(new RuntimeException()) + .when(mMockIPackageManager) + .getInstalledApplications(anyLong(), anyInt()); + + assertNull(BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager)); + } + + @Test + public void testGetInstalledApplications_returnInstalledApps() throws Exception { + final UserInfo userInfo = + new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0); + doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt()); + + final ApplicationInfo applicationInfo1 = new ApplicationInfo(); + applicationInfo1.enabled = true; + applicationInfo1.uid = 1; + final ApplicationInfo applicationInfo2 = new ApplicationInfo(); + applicationInfo2.enabled = false; + applicationInfo2.uid = 2; + applicationInfo2.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; + final ApplicationInfo applicationInfo3 = new ApplicationInfo(); + applicationInfo3.enabled = false; + applicationInfo3.uid = 3; + applicationInfo3.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + final ApplicationInfo applicationInfo4 = new ApplicationInfo(); + applicationInfo4.enabled = true; + applicationInfo4.uid = 4; + applicationInfo4.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; + doReturn(new ParceledListSlice( + Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3, applicationInfo4))) + .when(mMockIPackageManager) + .getInstalledApplications(anyLong(), anyInt()); + + final ArraySet applications = + BatteryOptimizeUtils.getInstalledApplications(mContext, mMockIPackageManager); + assertThat(applications.size()).isEqualTo(3); + // applicationInfo3 should be filtered. + assertTrue(applications.contains(applicationInfo1)); + assertTrue(applications.contains(applicationInfo2)); + assertFalse(applications.contains(applicationInfo3)); + assertTrue(applications.contains(applicationInfo4)); + } + + @Test + public void testResetAppOptimizationMode_Optimized_verifyAction() throws Exception { + runTestForResetWithMode( + AppOpsManager.MODE_ALLOWED, /* allowListed */ false, + /* isSystemOrDefaultApp */ false); + + verifyZeroInteractions(mMockBatteryUtils); + + final InOrder inOrder = inOrder(mMockBackend); + inOrder.verify(mMockBackend).refreshList(); + inOrder.verify(mMockBackend).isAllowlisted(PACKAGE_NAME); + verifyNoMoreInteractions(mMockBackend); + } + + @Test + public void testResetAppOptimizationMode_SystemOrDefault_verifyAction() throws Exception { + runTestForResetWithMode( + AppOpsManager.MODE_ALLOWED, /* allowListed */ true, + /* isSystemOrDefaultApp */ true); + + verifyZeroInteractions(mMockBatteryUtils); + + final InOrder inOrder = inOrder(mMockBackend); + inOrder.verify(mMockBackend).refreshList(); + inOrder.verify(mMockBackend).isAllowlisted(PACKAGE_NAME); + inOrder.verify(mMockBackend).isSysAllowlisted(PACKAGE_NAME); + verifyNoMoreInteractions(mMockBackend); + } + + @Test + public void testResetAppOptimizationMode_Restricted_verifyAction() throws Exception { + runTestForResetWithMode( + AppOpsManager.MODE_IGNORED, /* allowListed */ false, + /* isSystemOrDefaultApp */ false); + + verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false); + } + + @Test + public void testResetAppOptimizationMode_Unrestricted_verifyAction() throws Exception { + runTestForResetWithMode( + AppOpsManager.MODE_ALLOWED, /* allowListed */ true, + /* isSystemOrDefaultApp */ false); + + verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false); + } + + private void runTestForResetWithMode( + int appStandbyMode, boolean allowListed, boolean isSystemOrDefaultApp) + throws Exception { + final UserInfo userInfo = + new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0); + doReturn(Arrays.asList(userInfo)).when(mMockUserManager).getProfiles(anyInt()); + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.uid = UID; + applicationInfo.packageName = PACKAGE_NAME; + applicationInfo.enabled = true; + doReturn(new ParceledListSlice( + Arrays.asList(applicationInfo))) + .when(mMockIPackageManager) + .getInstalledApplications(anyLong(), anyInt()); + + doReturn(appStandbyMode) + .when(mMockAppOpsManager) + .checkOpNoThrow(anyInt(), anyInt(), anyString()); + doReturn(allowListed) + .when(mMockBackend) + .isAllowlisted(anyString()); + doReturn(isSystemOrDefaultApp) + .when(mMockBackend) + .isSysAllowlisted(anyString()); + doReturn(isSystemOrDefaultApp) + .when(mMockBackend) + .isDefaultActiveApp(anyString()); + + BatteryOptimizeUtils.resetAppOptimizationMode( + mContext, mMockIPackageManager, mMockAppOpsManager, mMockBackend, + mMockBatteryUtils); + TimeUnit.SECONDS.sleep(1); + } + + private void verifySetAppOptimizationMode(int appStandbyMode, boolean allowListed) { + verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, appStandbyMode); + if (allowListed) { + verify(mMockBackend).addApp(PACKAGE_NAME); + } else { + verify(mMockBackend).removeApp(PACKAGE_NAME); + } + } }