Reset Optimization Mode of apps when users reset app settings.

Fix the issue that Optimization Mode is not reset when users click the
"Reset apps" button in the setting.

Bug: 222037028
Test: make RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.fuelgauge" + emulator
Change-Id: I22fb8aa19e284e11882b2920b77b544dee4cc33c
This commit is contained in:
Kuan Wang
2022-05-10 19:41:42 +08:00
committed by KUAN WANG
parent c5ee465b14
commit 4028e6123c
5 changed files with 301 additions and 83 deletions

View File

@@ -38,6 +38,7 @@ import android.util.Log;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryOptimizeUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -152,6 +153,7 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener,
} catch (RemoteException e) { } catch (RemoteException e) {
} }
mAom.resetAllModes(); mAom.resetAllModes();
BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom);
final int[] restrictedUids = mNpm.getUidsWithPolicy( final int[] restrictedUids = mNpm.getUidsWithPolicy(
POLICY_REJECT_METERED_BACKGROUND); POLICY_REJECT_METERED_BACKGROUND);
final int currentUserId = ActivityManager.getCurrentUser(); final int currentUserId = ActivityManager.getCurrentUser();

View File

@@ -24,16 +24,13 @@ import android.app.backup.BackupHelper;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager; 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.Build;
import android.os.IDeviceIdleController; import android.os.IDeviceIdleController;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import androidx.annotation.VisibleForTesting; 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 String DEVICE_IDLE_SERVICE = "deviceidle";
private static final boolean DEBUG = Build.TYPE.equals("userdebug"); 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 = ",";
static final String DELIMITER_MODE = ":"; static final String DELIMITER_MODE = ":";
static final String KEY_FULL_POWER_LIST = "full_power_list"; static final String KEY_FULL_POWER_LIST = "full_power_list";
static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list"; static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
@VisibleForTesting @VisibleForTesting
List<ApplicationInfo> mTestApplicationInfoList = null; ArraySet<ApplicationInfo> mTestApplicationInfoList = null;
@VisibleForTesting @VisibleForTesting
PowerAllowlistBackend mPowerAllowlistBackend; PowerAllowlistBackend mPowerAllowlistBackend;
@@ -146,7 +134,7 @@ public final class BatteryBackupHelper implements BackupHelper {
@VisibleForTesting @VisibleForTesting
void backupOptimizationMode(BackupDataOutput data, List<String> allowlistedApps) { void backupOptimizationMode(BackupDataOutput data, List<String> allowlistedApps) {
final long timestamp = System.currentTimeMillis(); final long timestamp = System.currentTimeMillis();
final List<ApplicationInfo> applications = getInstalledApplications(); final ArraySet<ApplicationInfo> applications = getInstalledApplications();
if (applications == null || applications.isEmpty()) { if (applications == null || applications.isEmpty()) {
Log.w(TAG, "no data found in the getInstalledApplications()"); Log.w(TAG, "no data found in the getInstalledApplications()");
return; return;
@@ -269,36 +257,11 @@ public final class BatteryBackupHelper implements BackupHelper {
|| powerAllowlistBackend.isDefaultActiveApp(packageName); || powerAllowlistBackend.isDefaultActiveApp(packageName);
} }
private List<ApplicationInfo> getInstalledApplications() { private ArraySet<ApplicationInfo> getInstalledApplications() {
if (mTestApplicationInfoList != null) { if (mTestApplicationInfoList != null) {
return mTestApplicationInfoList; return mTestApplicationInfoList;
} }
final List<ApplicationInfo> applications = new ArrayList<>(); return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager());
final UserManager um = mContext.getSystemService(UserManager.class);
for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
try {
@SuppressWarnings("unchecked")
final ParceledListSlice<ApplicationInfo> 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;
} }
private void debugLog(String debugContent) { private void debugLog(String debugContent) {

View File

@@ -19,7 +19,15 @@ package com.android.settings.fuelgauge;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.content.Context; 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.AsyncTask;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -43,6 +51,15 @@ public class BatteryOptimizeUtils {
private final String mPackageName; private final String mPackageName;
private final int mUid; 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. // Optimization modes.
static final int MODE_UNKNOWN = 0; static final int MODE_UNKNOWN = 0;
static final int MODE_RESTRICTED = 1; static final int MODE_RESTRICTED = 1;
@@ -90,28 +107,20 @@ public class BatteryOptimizeUtils {
return getAppOptimizationMode(mMode, mAllowListed); 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. */ /** Sets the {@link OptimizationMode} for associated app. */
public void setAppUsageState(@OptimizationMode int mode) { public void setAppUsageState(@OptimizationMode int mode) {
if (getAppOptimizationMode(mMode, mAllowListed) == mode) { if (getAppOptimizationMode(mMode, mAllowListed) == mode) {
Log.w(TAG, "set the same optimization mode for: " + mPackageName); Log.w(TAG, "set the same optimization mode for: " + mPackageName);
return; return;
} }
setAppUsageStateInternal(mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend);
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.");
}
});
} }
/** /**
@@ -126,25 +135,111 @@ public class BatteryOptimizeUtils {
*/ */
public boolean isSystemOrDefaultApp() { public boolean isSystemOrDefaultApp() {
mPowerAllowListBackend.refreshList(); mPowerAllowListBackend.refreshList();
return isSystemOrDefaultApp(mPowerAllowListBackend, mPackageName);
}
return mPowerAllowListBackend.isSysAllowlisted(mPackageName) /**
|| mPowerAllowListBackend.isDefaultActiveApp(mPackageName); * Gets the list of installed applications.
*/
public static ArraySet<ApplicationInfo> getInstalledApplications(
Context context, IPackageManager ipm) {
final ArraySet<ApplicationInfo> applications = new ArraySet<>();
final UserManager um = context.getSystemService(UserManager.class);
for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
try {
@SuppressWarnings("unchecked")
final ParceledListSlice<ApplicationInfo> 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<ApplicationInfo> 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() { String getPackageName() {
return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName; 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 { try {
mBatteryUtils.setForceAppStandby(mUid, mPackageName, appStandbyMode); batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode);
if (allowListed) { if (allowListed) {
mPowerAllowListBackend.addApp(mPackageName); powerAllowlistBackend.addApp(packageName);
} else { } else {
mPowerAllowListBackend.removeApp(mPackageName); powerAllowlistBackend.removeApp(packageName);
} }
} catch (Exception e) { } 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 mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName); .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d", Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d",
mPackageName, mPackageName, mAllowListed, mMode));
mAllowListed,
mMode));
} }
} }

View File

@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
@@ -48,6 +49,7 @@ import android.os.IDeviceIdleController;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.util.ArraySet;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend; import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
@@ -193,7 +195,7 @@ public final class BatteryBackupHelperTest {
doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt()); doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt());
doThrow(new RuntimeException()) doThrow(new RuntimeException())
.when(mIPackageManager) .when(mIPackageManager)
.getInstalledApplications(anyInt(), anyInt()); .getInstalledApplications(anyLong(), anyInt());
mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, null); mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, null);
@@ -369,7 +371,7 @@ public final class BatteryBackupHelperTest {
doReturn(new ParceledListSlice<ApplicationInfo>( doReturn(new ParceledListSlice<ApplicationInfo>(
Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3))) Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3)))
.when(mIPackageManager) .when(mIPackageManager)
.getInstalledApplications(anyInt(), anyInt()); .getInstalledApplications(anyLong(), anyInt());
// Sets the AppOpsManager for checkOpNoThrow() method. // Sets the AppOpsManager for checkOpNoThrow() method.
doReturn(AppOpsManager.MODE_ALLOWED) doReturn(AppOpsManager.MODE_ALLOWED)
.when(mAppOpsManager) .when(mAppOpsManager)
@@ -384,7 +386,7 @@ public final class BatteryBackupHelperTest {
applicationInfo2.uid, applicationInfo2.uid,
applicationInfo2.packageName); applicationInfo2.packageName);
mBatteryBackupHelper.mTestApplicationInfoList = mBatteryBackupHelper.mTestApplicationInfoList =
Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3); new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3));
} }
@Implements(UserHandle.class) @Implements(UserHandle.class)

View File

@@ -22,26 +22,43 @@ import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRIC
import static com.google.common.truth.Truth.assertThat; 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.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString; 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.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.content.Context; 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 com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.Arrays;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@@ -50,9 +67,11 @@ public class BatteryOptimizeUtilsTest {
private static final int UID = 12345; private static final int UID = 12345;
private static final String PACKAGE_NAME = "com.android.app"; private static final String PACKAGE_NAME = "com.android.app";
@Mock BatteryUtils mMockBatteryUtils; @Mock private BatteryUtils mMockBatteryUtils;
@Mock AppOpsManager mMockAppOpsManager; @Mock private AppOpsManager mMockAppOpsManager;
@Mock PowerAllowlistBackend mMockBackend; @Mock private PowerAllowlistBackend mMockBackend;
@Mock private IPackageManager mMockIPackageManager;
@Mock private UserManager mMockUserManager;
private Context mContext; private Context mContext;
private BatteryOptimizeUtils mBatteryOptimizeUtils; private BatteryOptimizeUtils mBatteryOptimizeUtils;
@@ -68,6 +87,7 @@ public class BatteryOptimizeUtilsTest {
// Sets the default mode as MODE_RESTRICTED. // Sets the default mode as MODE_RESTRICTED.
mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_IGNORED; mBatteryOptimizeUtils.mMode = AppOpsManager.MODE_IGNORED;
mBatteryOptimizeUtils.mAllowListed = false; mBatteryOptimizeUtils.mAllowListed = false;
doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
} }
@Test @Test
@@ -135,9 +155,7 @@ public class BatteryOptimizeUtilsTest {
mBatteryOptimizeUtils.setAppUsageState(MODE_RESTRICTED); mBatteryOptimizeUtils.setAppUsageState(MODE_RESTRICTED);
TimeUnit.SECONDS.sleep(1); TimeUnit.SECONDS.sleep(1);
verify(mMockBatteryUtils).setForceAppStandby(UID, verifySetAppOptimizationMode(AppOpsManager.MODE_IGNORED, /* allowListed */ false);
PACKAGE_NAME, AppOpsManager.MODE_IGNORED);
verify(mMockBackend).removeApp(PACKAGE_NAME);
} }
@Test @Test
@@ -145,9 +163,7 @@ public class BatteryOptimizeUtilsTest {
mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED); mBatteryOptimizeUtils.setAppUsageState(MODE_UNRESTRICTED);
TimeUnit.SECONDS.sleep(1); TimeUnit.SECONDS.sleep(1);
verify(mMockBatteryUtils).setForceAppStandby(UID, verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ true);
PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
verify(mMockBackend).addApp(PACKAGE_NAME);
} }
@Test @Test
@@ -155,9 +171,7 @@ public class BatteryOptimizeUtilsTest {
mBatteryOptimizeUtils.setAppUsageState(MODE_OPTIMIZED); mBatteryOptimizeUtils.setAppUsageState(MODE_OPTIMIZED);
TimeUnit.SECONDS.sleep(1); TimeUnit.SECONDS.sleep(1);
verify(mMockBatteryUtils).setForceAppStandby(UID, verifySetAppOptimizationMode(AppOpsManager.MODE_ALLOWED, /* allowListed */ false);
PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
verify(mMockBackend).removeApp(PACKAGE_NAME);
} }
@Test @Test
@@ -172,4 +186,148 @@ public class BatteryOptimizeUtilsTest {
verifyZeroInteractions(mMockBackend); verifyZeroInteractions(mMockBackend);
verifyZeroInteractions(mMockBatteryUtils); 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<ApplicationInfo>(
Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3, applicationInfo4)))
.when(mMockIPackageManager)
.getInstalledApplications(anyLong(), anyInt());
final ArraySet<ApplicationInfo> 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<ApplicationInfo>(
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);
}
}
} }