Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d088856b authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Make apps active when charging."

parents 29fa4efd f35ed370
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
+44 −9
Original line number Diff line number Diff line
@@ -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() {
+2 −1
Original line number Diff line number Diff line
@@ -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
     */
+54 −0
Original line number Diff line number Diff line
@@ -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);