Merge "Make apps active when charging."
This commit is contained in:
@@ -85,6 +85,7 @@ public interface AppStandbyInternal {
|
||||
/**
|
||||
* Checks if an app has been idle for a while and filters out apps that are excluded.
|
||||
* It returns false if the current system state allows all apps to be considered active.
|
||||
* This happens if the device is plugged in or otherwise temporarily allowed to make exceptions.
|
||||
* Called by interface impls.
|
||||
*/
|
||||
boolean isAppIdleFiltered(String packageName, int appId, int userId,
|
||||
|
||||
@@ -48,6 +48,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
|
||||
|
||||
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
|
||||
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -71,9 +72,8 @@ import android.content.pm.ParceledListSlice;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.NetworkScoreManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
@@ -285,6 +285,7 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
long mInitialForegroundServiceStartTimeoutMillis;
|
||||
|
||||
private volatile boolean mAppIdleEnabled;
|
||||
private boolean mIsCharging;
|
||||
private boolean mSystemServicesReady = false;
|
||||
// There was a system update, defaults need to be initialized after services are ready
|
||||
private boolean mPendingInitializeDefaults;
|
||||
@@ -360,6 +361,11 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
mHandler = new AppStandbyHandler(mInjector.getLooper());
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
|
||||
DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
|
||||
IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
|
||||
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
|
||||
mContext.registerReceiver(deviceStateReceiver, deviceStates);
|
||||
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
|
||||
mInjector.elapsedRealtime());
|
||||
@@ -417,6 +423,8 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
if (mPendingOneTimeCheckIdleStates) {
|
||||
postOneTimeCheckIdleStates();
|
||||
}
|
||||
} else if (phase == PHASE_BOOT_COMPLETED) {
|
||||
setChargingState(mInjector.isCharging());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,6 +523,16 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
appUsage.bucketingReason, false);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setChargingState(boolean isCharging) {
|
||||
synchronized (mAppIdleLock) {
|
||||
if (mIsCharging != isCharging) {
|
||||
if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
|
||||
mIsCharging = isCharging;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCheckIdleStates(int userId) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
|
||||
@@ -977,6 +995,11 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
if (isAppSpecial(packageName, appId, userId)) {
|
||||
return false;
|
||||
} else {
|
||||
synchronized (mAppIdleLock) {
|
||||
if (!mAppIdleEnabled || mIsCharging) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
|
||||
}
|
||||
}
|
||||
@@ -1543,6 +1566,8 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
|
||||
pw.println();
|
||||
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
|
||||
pw.print(" mIsCharging=");
|
||||
pw.print(mIsCharging);
|
||||
pw.println();
|
||||
pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
|
||||
pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
|
||||
@@ -1560,6 +1585,7 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
private final Looper mLooper;
|
||||
private IDeviceIdleController mDeviceIdleController;
|
||||
private IBatteryStats mBatteryStats;
|
||||
private BatteryManager mBatteryManager;
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
private DisplayManager mDisplayManager;
|
||||
private PowerManager mPowerManager;
|
||||
@@ -1593,6 +1619,7 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
mDisplayManager = (DisplayManager) mContext.getSystemService(
|
||||
Context.DISPLAY_SERVICE);
|
||||
mPowerManager = mContext.getSystemService(PowerManager.class);
|
||||
mBatteryManager = mContext.getSystemService(BatteryManager.class);
|
||||
|
||||
final ActivityManager activityManager =
|
||||
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
@@ -1630,6 +1657,10 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
return buildFlag && runtimeFlag;
|
||||
}
|
||||
|
||||
boolean isCharging() {
|
||||
return mBatteryManager.isCharging();
|
||||
}
|
||||
|
||||
boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
|
||||
return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName);
|
||||
}
|
||||
@@ -1766,15 +1797,19 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
}
|
||||
};
|
||||
|
||||
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build();
|
||||
|
||||
private final ConnectivityManager.NetworkCallback mNetworkCallback
|
||||
= new ConnectivityManager.NetworkCallback() {
|
||||
private class DeviceStateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
mConnectivityManager.unregisterNetworkCallback(this);
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case BatteryManager.ACTION_CHARGING:
|
||||
setChargingState(true);
|
||||
break;
|
||||
case BatteryManager.ACTION_DISCHARGING:
|
||||
setChargingState(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final DisplayManager.DisplayListener mDisplayListener
|
||||
= new DisplayManager.DisplayListener() {
|
||||
|
||||
@@ -599,7 +599,8 @@ public final class UsageStatsManager {
|
||||
/**
|
||||
* Returns whether the specified app is currently considered inactive. This will be true if the
|
||||
* app hasn't been used directly or indirectly for a period of time defined by the system. This
|
||||
* could be of the order of several hours or days.
|
||||
* could be of the order of several hours or days. Apps are not considered inactive when the
|
||||
* device is charging.
|
||||
* @param packageName The package name of the app to query
|
||||
* @return whether the app is currently considered inactive
|
||||
*/
|
||||
|
||||
@@ -145,6 +145,7 @@ public class AppStandbyControllerTests {
|
||||
static class MyInjector extends AppStandbyController.Injector {
|
||||
long mElapsedRealtime;
|
||||
boolean mIsAppIdleEnabled = true;
|
||||
boolean mIsCharging;
|
||||
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
|
||||
boolean mDisplayOn;
|
||||
DisplayManager.DisplayListener mDisplayListener;
|
||||
@@ -178,6 +179,11 @@ public class AppStandbyControllerTests {
|
||||
return mIsAppIdleEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isCharging() {
|
||||
return mIsCharging;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
|
||||
return mPowerSaveWhitelistExceptIdle.contains(packageName);
|
||||
@@ -281,6 +287,13 @@ public class AppStandbyControllerTests {
|
||||
} catch (PackageManager.NameNotFoundException nnfe) {}
|
||||
}
|
||||
|
||||
private void setChargingState(AppStandbyController controller, boolean charging) {
|
||||
mInjector.mIsCharging = charging;
|
||||
if (controller != null) {
|
||||
controller.setChargingState(charging);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
|
||||
mInjector.mIsAppIdleEnabled = enabled;
|
||||
if (controller != null) {
|
||||
@@ -297,6 +310,7 @@ public class AppStandbyControllerTests {
|
||||
controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
||||
mInjector.setDisplayOn(false);
|
||||
mInjector.setDisplayOn(true);
|
||||
setChargingState(controller, false);
|
||||
controller.checkIdleStates(USER_ID);
|
||||
assertNotEquals(STANDBY_BUCKET_EXEMPTED,
|
||||
controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
|
||||
@@ -324,6 +338,46 @@ public class AppStandbyControllerTests {
|
||||
mInjector.mElapsedRealtime, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppIdle_Charging() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_FORCED_BY_SYSTEM);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
|
||||
setChargingState(mController, true);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
|
||||
setChargingState(mController, false);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppIdle_Enabled() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
setAppIdleEnabled(mController, true);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_FORCED_BY_SYSTEM);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
|
||||
setAppIdleEnabled(mController, false);
|
||||
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
|
||||
setAppIdleEnabled(mController, true);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
|
||||
assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
|
||||
}
|
||||
|
||||
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
|
||||
mInjector.mElapsedRealtime = elapsedTime;
|
||||
controller.checkIdleStates(USER_ID);
|
||||
|
||||
Reference in New Issue
Block a user