Initial unit test for DeviceIdleController.
This just tests the standard progression into deep idle mode. Exit conditions and light idle flow is not tested yet. Bug: 116512267 Test: atest com.android.server.DeviceIdleControllerTest Change-Id: I015c10871cd00d7a6be19c0b13fd4b3926c9fdf0
This commit is contained in:
@@ -77,6 +77,7 @@ import android.util.TimeUtils;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
@@ -104,6 +105,8 @@ import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Keeps track of device idleness and drives low power mode based on that.
|
||||
*
|
||||
* Test: atest com.android.server.DeviceIdleControllerTest
|
||||
*/
|
||||
public class DeviceIdleController extends SystemService
|
||||
implements AnyMotionDetector.DeviceIdleCallback {
|
||||
@@ -148,21 +151,29 @@ public class DeviceIdleController extends SystemService
|
||||
private boolean mScreenLocked;
|
||||
|
||||
/** Device is currently active. */
|
||||
private static final int STATE_ACTIVE = 0;
|
||||
@VisibleForTesting
|
||||
static final int STATE_ACTIVE = 0;
|
||||
/** Device is inactive (screen off, no motion) and we are waiting to for idle. */
|
||||
private static final int STATE_INACTIVE = 1;
|
||||
@VisibleForTesting
|
||||
static final int STATE_INACTIVE = 1;
|
||||
/** Device is past the initial inactive period, and waiting for the next idle period. */
|
||||
private static final int STATE_IDLE_PENDING = 2;
|
||||
@VisibleForTesting
|
||||
static final int STATE_IDLE_PENDING = 2;
|
||||
/** Device is currently sensing motion. */
|
||||
private static final int STATE_SENSING = 3;
|
||||
@VisibleForTesting
|
||||
static final int STATE_SENSING = 3;
|
||||
/** Device is currently finding location (and may still be sensing). */
|
||||
private static final int STATE_LOCATING = 4;
|
||||
@VisibleForTesting
|
||||
static final int STATE_LOCATING = 4;
|
||||
/** Device is in the idle state, trying to stay asleep as much as possible. */
|
||||
private static final int STATE_IDLE = 5;
|
||||
@VisibleForTesting
|
||||
static final int STATE_IDLE = 5;
|
||||
/** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
|
||||
private static final int STATE_IDLE_MAINTENANCE = 6;
|
||||
@VisibleForTesting
|
||||
static final int STATE_IDLE_MAINTENANCE = 6;
|
||||
|
||||
private static String stateToString(int state) {
|
||||
@VisibleForTesting
|
||||
static String stateToString(int state) {
|
||||
switch (state) {
|
||||
case STATE_ACTIVE: return "ACTIVE";
|
||||
case STATE_INACTIVE: return "INACTIVE";
|
||||
@@ -176,21 +187,30 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
|
||||
/** Device is currently active. */
|
||||
private static final int LIGHT_STATE_ACTIVE = 0;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_ACTIVE = 0;
|
||||
/** Device is inactive (screen off) and we are waiting to for the first light idle. */
|
||||
private static final int LIGHT_STATE_INACTIVE = 1;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_INACTIVE = 1;
|
||||
/** Device is about to go idle for the first time, wait for current work to complete. */
|
||||
private static final int LIGHT_STATE_PRE_IDLE = 3;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_PRE_IDLE = 3;
|
||||
/** Device is in the light idle state, trying to stay asleep as much as possible. */
|
||||
private static final int LIGHT_STATE_IDLE = 4;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_IDLE = 4;
|
||||
/** Device is in the light idle state, we want to go in to idle maintenance but are
|
||||
* waiting for network connectivity before doing so. */
|
||||
private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;
|
||||
/** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
|
||||
private static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
|
||||
/** Device light idle state is overriden, now applying deep doze state. */
|
||||
private static final int LIGHT_STATE_OVERRIDE = 7;
|
||||
private static String lightStateToString(int state) {
|
||||
@VisibleForTesting
|
||||
static final int LIGHT_STATE_OVERRIDE = 7;
|
||||
|
||||
@VisibleForTesting
|
||||
static String lightStateToString(int state) {
|
||||
switch (state) {
|
||||
case LIGHT_STATE_ACTIVE: return "ACTIVE";
|
||||
case LIGHT_STATE_INACTIVE: return "INACTIVE";
|
||||
@@ -382,6 +402,8 @@ public class DeviceIdleController extends SystemService
|
||||
public void onAlarm() {
|
||||
if (mState == STATE_SENSING) {
|
||||
synchronized (DeviceIdleController.this) {
|
||||
// Restart the device idle progression in case the device moved but the screen
|
||||
// didn't turn on.
|
||||
becomeInactiveIfAppropriateLocked();
|
||||
}
|
||||
}
|
||||
@@ -422,11 +444,16 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
};
|
||||
|
||||
private final class MotionListener extends TriggerEventListener
|
||||
@VisibleForTesting
|
||||
final class MotionListener extends TriggerEventListener
|
||||
implements SensorEventListener {
|
||||
|
||||
boolean active = false;
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrigger(TriggerEvent event) {
|
||||
synchronized (DeviceIdleController.this) {
|
||||
@@ -472,7 +499,7 @@ public class DeviceIdleController extends SystemService
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
private final MotionListener mMotionListener = new MotionListener();
|
||||
@VisibleForTesting final MotionListener mMotionListener = new MotionListener();
|
||||
|
||||
private final LocationListener mGenericLocationListener = new LocationListener() {
|
||||
@Override
|
||||
@@ -594,7 +621,7 @@ public class DeviceIdleController extends SystemService
|
||||
public float LIGHT_IDLE_FACTOR;
|
||||
|
||||
/**
|
||||
* This is the maximum time we will run in idle maintenence mode.
|
||||
* This is the maximum time we will run in idle maintenance mode.
|
||||
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
|
||||
* @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
|
||||
*/
|
||||
@@ -1360,6 +1387,45 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
static class Injector {
|
||||
private final Context mContext;
|
||||
|
||||
Injector(Context ctx) {
|
||||
mContext = ctx;
|
||||
}
|
||||
|
||||
AlarmManager getAlarmManager() {
|
||||
return mContext.getSystemService(AlarmManager.class);
|
||||
}
|
||||
|
||||
AnyMotionDetector getAnyMotionDetector(Handler handler, SensorManager sm,
|
||||
AnyMotionDetector.DeviceIdleCallback callback, float angleThreshold) {
|
||||
return new AnyMotionDetector(getPowerManager(), handler, sm, callback, angleThreshold);
|
||||
}
|
||||
|
||||
AppStateTracker getAppStateTracker(Context ctx, Looper looper) {
|
||||
return new AppStateTracker(ctx, looper);
|
||||
}
|
||||
|
||||
ConnectivityService getConnectivityService() {
|
||||
return (ConnectivityService) ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
LocationManager getLocationManager() {
|
||||
return mContext.getSystemService(LocationManager.class);
|
||||
}
|
||||
|
||||
MyHandler getHandler(DeviceIdleController ctlr) {
|
||||
return ctlr.new MyHandler(BackgroundThread.getHandler().getLooper());
|
||||
}
|
||||
|
||||
PowerManager getPowerManager() {
|
||||
return mContext.getSystemService(PowerManager.class);
|
||||
}
|
||||
}
|
||||
|
||||
private final Injector mInjector;
|
||||
|
||||
private ActivityTaskManagerInternal.ScreenObserver mScreenObserver =
|
||||
new ActivityTaskManagerInternal.ScreenObserver() {
|
||||
@Override
|
||||
@@ -1373,14 +1439,19 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
};
|
||||
|
||||
public DeviceIdleController(Context context) {
|
||||
@VisibleForTesting DeviceIdleController(Context context, Injector injector) {
|
||||
super(context);
|
||||
mInjector = injector;
|
||||
mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
|
||||
mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
|
||||
mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper());
|
||||
mHandler = mInjector.getHandler(this);
|
||||
mAppStateTracker = mInjector.getAppStateTracker(context, FgThread.get().getLooper());
|
||||
LocalServices.addService(AppStateTracker.class, mAppStateTracker);
|
||||
}
|
||||
|
||||
public DeviceIdleController(Context context) {
|
||||
this(context, new Injector(context));
|
||||
}
|
||||
|
||||
boolean isAppOnWhitelistInternal(int appid) {
|
||||
synchronized (this) {
|
||||
return Arrays.binarySearch(mPowerSaveWhitelistAllAppIdArray, appid) >= 0;
|
||||
@@ -1459,20 +1530,19 @@ public class DeviceIdleController extends SystemService
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == PHASE_SYSTEM_SERVICES_READY) {
|
||||
synchronized (this) {
|
||||
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
mAlarmManager = mInjector.getAlarmManager();
|
||||
mBatteryStats = BatteryStatsService.getService();
|
||||
mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
|
||||
mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
|
||||
mLocalPowerManager = getLocalService(PowerManagerInternal.class);
|
||||
mPowerManager = getContext().getSystemService(PowerManager.class);
|
||||
mPowerManager = mInjector.getPowerManager();
|
||||
mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"deviceidle_maint");
|
||||
mActiveIdleWakeLock.setReferenceCounted(false);
|
||||
mGoingIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"deviceidle_going_idle");
|
||||
mGoingIdleWakeLock.setReferenceCounted(true);
|
||||
mConnectivityService = (ConnectivityService)ServiceManager.getService(
|
||||
Context.CONNECTIVITY_SERVICE);
|
||||
mConnectivityService = mInjector.getConnectivityService();
|
||||
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
||||
mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
|
||||
@@ -1495,8 +1565,7 @@ public class DeviceIdleController extends SystemService
|
||||
|
||||
if (getContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
|
||||
mLocationManager = (LocationManager) getContext().getSystemService(
|
||||
Context.LOCATION_SERVICE);
|
||||
mLocationManager = mInjector.getLocationManager();
|
||||
mLocationRequest = new LocationRequest()
|
||||
.setQuality(LocationRequest.ACCURACY_FINE)
|
||||
.setInterval(0)
|
||||
@@ -1506,9 +1575,8 @@ public class DeviceIdleController extends SystemService
|
||||
|
||||
float angleThreshold = getContext().getResources().getInteger(
|
||||
com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
|
||||
mAnyMotionDetector = new AnyMotionDetector(
|
||||
(PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
|
||||
mHandler, mSensorManager, this, angleThreshold);
|
||||
mAnyMotionDetector = mInjector.getAnyMotionDetector(mHandler, mSensorManager, this,
|
||||
angleThreshold);
|
||||
|
||||
mAppStateTracker.onSystemServicesReady();
|
||||
|
||||
@@ -2005,6 +2073,11 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isScreenOn() {
|
||||
return mScreenOn;
|
||||
}
|
||||
|
||||
void updateInteractivityLocked() {
|
||||
// The interactivity state from the power manager tells us whether the display is
|
||||
// in a state that we need to keep things running so they will update at a normal
|
||||
@@ -2024,6 +2097,11 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isCharging() {
|
||||
return mCharging;
|
||||
}
|
||||
|
||||
void updateChargingLocked(boolean charging) {
|
||||
if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
|
||||
if (!charging && mCharging) {
|
||||
@@ -2071,6 +2149,18 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
/** Must only be used in tests. */
|
||||
@VisibleForTesting
|
||||
void setDeepEnabledForTest(boolean enabled) {
|
||||
mDeepEnabled = enabled;
|
||||
}
|
||||
|
||||
/** Must only be used in tests. */
|
||||
@VisibleForTesting
|
||||
void setLightEnabledForTest(boolean enabled) {
|
||||
mLightEnabled = enabled;
|
||||
}
|
||||
|
||||
void becomeInactiveIfAppropriateLocked() {
|
||||
if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
|
||||
if ((!mScreenOn && !mCharging) || mForceIdle) {
|
||||
@@ -2093,7 +2183,7 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
void resetIdleManagementLocked() {
|
||||
private void resetIdleManagementLocked() {
|
||||
mNextIdlePendingDelay = 0;
|
||||
mNextIdleDelay = 0;
|
||||
mNextLightIdleDelay = 0;
|
||||
@@ -2104,7 +2194,7 @@ public class DeviceIdleController extends SystemService
|
||||
mAnyMotionDetector.stop();
|
||||
}
|
||||
|
||||
void resetLightIdleManagementLocked() {
|
||||
private void resetLightIdleManagementLocked() {
|
||||
cancelLightAlarmLocked();
|
||||
}
|
||||
|
||||
@@ -2117,6 +2207,11 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getLightState() {
|
||||
return mLightState;
|
||||
}
|
||||
|
||||
void stepLightIdleStateLocked(String reason) {
|
||||
if (mLightState == LIGHT_STATE_OVERRIDE) {
|
||||
// If we are already in deep device idle mode, then
|
||||
@@ -2200,6 +2295,18 @@ public class DeviceIdleController extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
/** Must only be used in tests. */
|
||||
@VisibleForTesting
|
||||
void setLocationManagerForTest(LocationManager lm) {
|
||||
mLocationManager = lm;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void stepIdleStateLocked(String reason) {
|
||||
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
|
||||
EventLogTags.writeDeviceIdleStep();
|
||||
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getContext;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_ACTIVE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_IDLE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_IDLE_MAINTENANCE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_INACTIVE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_OVERRIDE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_PRE_IDLE;
|
||||
import static com.android.server.DeviceIdleController.LIGHT_STATE_WAITING_FOR_NETWORK;
|
||||
import static com.android.server.DeviceIdleController.STATE_ACTIVE;
|
||||
import static com.android.server.DeviceIdleController.STATE_IDLE;
|
||||
import static com.android.server.DeviceIdleController.STATE_IDLE_MAINTENANCE;
|
||||
import static com.android.server.DeviceIdleController.STATE_IDLE_PENDING;
|
||||
import static com.android.server.DeviceIdleController.STATE_INACTIVE;
|
||||
import static com.android.server.DeviceIdleController.STATE_LOCATING;
|
||||
import static com.android.server.DeviceIdleController.STATE_SENSING;
|
||||
import static com.android.server.DeviceIdleController.lightStateToString;
|
||||
import static com.android.server.DeviceIdleController.stateToString;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManagerInternal;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.net.NetworkPolicyManagerInternal;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
/**
|
||||
* Tests for {@link com.android.server.DeviceIdleController}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DeviceIdleControllerTest {
|
||||
private DeviceIdleController mDeviceIdleController;
|
||||
private AnyMotionDetectorForTest mAnyMotionDetector;
|
||||
private AppStateTrackerForTest mAppStateTracker;
|
||||
|
||||
private MockitoSession mMockingSession;
|
||||
@Mock
|
||||
private PowerManager mPowerManager;
|
||||
@Mock
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
@Mock
|
||||
private AlarmManager mAlarmManager;
|
||||
@Mock
|
||||
private LocationManager mLocationManager;
|
||||
@Mock
|
||||
private IActivityManager mIActivityManager;
|
||||
|
||||
class InjectorForTest extends DeviceIdleController.Injector {
|
||||
|
||||
InjectorForTest(Context ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
AlarmManager getAlarmManager() {
|
||||
return mAlarmManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
AnyMotionDetector getAnyMotionDetector(Handler handler, SensorManager sm,
|
||||
AnyMotionDetector.DeviceIdleCallback callback, float angleThreshold) {
|
||||
return mAnyMotionDetector;
|
||||
}
|
||||
|
||||
@Override
|
||||
AppStateTracker getAppStateTracker(Context ctx, Looper loop) {
|
||||
return mAppStateTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
ConnectivityService getConnectivityService() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
LocationManager getLocationManager() {
|
||||
return mLocationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
DeviceIdleController.MyHandler getHandler(DeviceIdleController ctlr) {
|
||||
return mock(DeviceIdleController.MyHandler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
PowerManager getPowerManager() {
|
||||
return mPowerManager;
|
||||
}
|
||||
}
|
||||
|
||||
private class AnyMotionDetectorForTest extends AnyMotionDetector {
|
||||
boolean isMonitoring = false;
|
||||
|
||||
AnyMotionDetectorForTest() {
|
||||
super(mPowerManager, mock(Handler.class), mock(SensorManager.class),
|
||||
mock(DeviceIdleCallback.class), 0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkForAnyMotion() {
|
||||
isMonitoring = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
isMonitoring = false;
|
||||
}
|
||||
}
|
||||
|
||||
private class AppStateTrackerForTest extends AppStateTracker {
|
||||
AppStateTrackerForTest(Context ctx, Looper looper) {
|
||||
super(ctx, looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemServicesReady() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
IActivityManager injectIActivityManager() {
|
||||
return mIActivityManager;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMockingSession = mockitoSession()
|
||||
.initMocks(this)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.mockStatic(LocalServices.class)
|
||||
.startMocking();
|
||||
doReturn(mock(ActivityManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(ActivityManagerInternal.class));
|
||||
doReturn(mock(ActivityTaskManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(ActivityTaskManagerInternal.class));
|
||||
doReturn(mock(PowerManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(PowerManagerInternal.class));
|
||||
doReturn(mock(NetworkPolicyManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
|
||||
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
|
||||
doNothing().when(mWakeLock).acquire();
|
||||
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
|
||||
mAnyMotionDetector = new AnyMotionDetectorForTest();
|
||||
mDeviceIdleController = new DeviceIdleController(getContext(),
|
||||
new InjectorForTest(getContext()));
|
||||
spyOn(mDeviceIdleController);
|
||||
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
|
||||
mDeviceIdleController.onStart();
|
||||
mDeviceIdleController.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
|
||||
mDeviceIdleController.setDeepEnabledForTest(true);
|
||||
mDeviceIdleController.setLightEnabledForTest(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (mMockingSession != null) {
|
||||
mMockingSession.finishMocking();
|
||||
}
|
||||
// DeviceIdleController adds this to LocalServices in the constructor, so we have to remove
|
||||
// it after each test, otherwise, subsequent tests will fail.
|
||||
LocalServices.removeServiceForTest(AppStateTracker.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInteractivityLocked() {
|
||||
doReturn(false).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
|
||||
// Make sure setting false when screen is already off doesn't change anything.
|
||||
doReturn(false).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
|
||||
// Test changing from screen off to screen on.
|
||||
doReturn(true).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
assertTrue(mDeviceIdleController.isScreenOn());
|
||||
|
||||
// Make sure setting true when screen is already on doesn't change anything.
|
||||
doReturn(true).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
assertTrue(mDeviceIdleController.isScreenOn());
|
||||
|
||||
// Test changing from screen on to screen off.
|
||||
doReturn(false).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChargingLocked() {
|
||||
mDeviceIdleController.updateChargingLocked(false);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
|
||||
// Make sure setting false when charging is already off doesn't change anything.
|
||||
mDeviceIdleController.updateChargingLocked(false);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
|
||||
// Test changing from charging off to charging on.
|
||||
mDeviceIdleController.updateChargingLocked(true);
|
||||
assertTrue(mDeviceIdleController.isCharging());
|
||||
|
||||
// Make sure setting true when charging is already on doesn't change anything.
|
||||
mDeviceIdleController.updateChargingLocked(true);
|
||||
assertTrue(mDeviceIdleController.isCharging());
|
||||
|
||||
// Test changing from charging on to charging off.
|
||||
mDeviceIdleController.updateChargingLocked(false);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateActiveToStateInactive_ConditionsNotMet() {
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with screen on and charging.
|
||||
setChargingOn(true);
|
||||
setScreenOn(true);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with charging on.
|
||||
setChargingOn(true);
|
||||
setScreenOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with screen on.
|
||||
// Note the different operation order here makes sure the state doesn't change before test.
|
||||
setScreenOn(true);
|
||||
setChargingOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLightStateActiveToLightStateInactive_ConditionsNotMet() {
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with screen on and charging.
|
||||
setChargingOn(true);
|
||||
setScreenOn(true);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with charging on.
|
||||
setChargingOn(true);
|
||||
setScreenOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
|
||||
|
||||
// State should stay ACTIVE with screen on.
|
||||
// Note the different operation order here makes sure the state doesn't change before test.
|
||||
setScreenOn(true);
|
||||
setChargingOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateActiveToStateInactive_ConditionsMet() {
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
|
||||
setChargingOn(false);
|
||||
setScreenOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyStateConditions(STATE_INACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLightStateActiveToLightStateInactive_ConditionsMet() {
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
|
||||
|
||||
setChargingOn(false);
|
||||
setScreenOn(false);
|
||||
|
||||
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
|
||||
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepIdleStateLocked_InvalidStates() {
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
// mDeviceIdleController.stepIdleStateLocked doesn't handle the ACTIVE case, so the state
|
||||
// should stay as ACTIVE.
|
||||
verifyStateConditions(STATE_ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepIdleStateLocked_ValidStates_NoLocationManager() {
|
||||
mDeviceIdleController.setLocationManagerForTest(null);
|
||||
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
|
||||
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
|
||||
// Set state to INACTIVE.
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
setChargingOn(false);
|
||||
setScreenOn(false);
|
||||
verifyStateConditions(STATE_INACTIVE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_PENDING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_SENSING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
// No location manager, so SENSING should go straight to IDLE.
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepIdleStateLocked_ValidStates_WithLocationManager_NoProviders() {
|
||||
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
|
||||
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
|
||||
// Set state to INACTIVE.
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
setChargingOn(false);
|
||||
setScreenOn(false);
|
||||
verifyStateConditions(STATE_INACTIVE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_PENDING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_SENSING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
// Location manager exists but there isn't a network or GPS provider,
|
||||
// so SENSING should go straight to IDLE.
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepIdleStateLocked_ValidStates_WithLocationManager_WithProviders() {
|
||||
doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
|
||||
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
|
||||
// TODO: add tests for when there's a wake-from-idle alarm coming soon.
|
||||
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
|
||||
// Set state to INACTIVE.
|
||||
mDeviceIdleController.becomeActiveLocked("testing", 0);
|
||||
setChargingOn(false);
|
||||
setScreenOn(false);
|
||||
verifyStateConditions(STATE_INACTIVE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_PENDING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_SENSING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
// Location manager exists with a provider, so SENSING should go to LOCATING.
|
||||
verifyStateConditions(STATE_LOCATING);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE);
|
||||
|
||||
mDeviceIdleController.stepIdleStateLocked("testing");
|
||||
verifyStateConditions(STATE_IDLE_MAINTENANCE);
|
||||
}
|
||||
|
||||
private void setChargingOn(boolean on) {
|
||||
mDeviceIdleController.updateChargingLocked(on);
|
||||
}
|
||||
|
||||
private void setScreenOn(boolean on) {
|
||||
doReturn(on).when(mPowerManager).isInteractive();
|
||||
mDeviceIdleController.updateInteractivityLocked();
|
||||
}
|
||||
|
||||
private void verifyStateConditions(int expectedState) {
|
||||
int curState = mDeviceIdleController.getState();
|
||||
assertEquals(
|
||||
"Expected " + stateToString(expectedState) + " but was " + stateToString(curState),
|
||||
expectedState, curState);
|
||||
|
||||
switch (expectedState) {
|
||||
case STATE_ACTIVE:
|
||||
assertFalse(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertFalse(mAnyMotionDetector.isMonitoring);
|
||||
break;
|
||||
case STATE_INACTIVE:
|
||||
assertFalse(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertFalse(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
case STATE_IDLE_PENDING:
|
||||
assertTrue(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertFalse(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
case STATE_SENSING:
|
||||
assertTrue(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertTrue(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
case STATE_LOCATING:
|
||||
assertTrue(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertTrue(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
case STATE_IDLE:
|
||||
assertTrue(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertFalse(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
// Light state should be OVERRIDE at this point.
|
||||
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
|
||||
break;
|
||||
case STATE_IDLE_MAINTENANCE:
|
||||
assertTrue(mDeviceIdleController.mMotionListener.isActive());
|
||||
assertFalse(mAnyMotionDetector.isMonitoring);
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
default:
|
||||
fail("Conditions for " + stateToString(expectedState) + " unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyLightStateConditions(int expectedLightState) {
|
||||
int curLightState = mDeviceIdleController.getLightState();
|
||||
assertEquals(
|
||||
"Expected " + lightStateToString(expectedLightState)
|
||||
+ " but was " + lightStateToString(curLightState),
|
||||
expectedLightState, curLightState);
|
||||
|
||||
switch (expectedLightState) {
|
||||
case LIGHT_STATE_ACTIVE:
|
||||
assertTrue(
|
||||
mDeviceIdleController.isCharging() || mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
case LIGHT_STATE_INACTIVE:
|
||||
case LIGHT_STATE_PRE_IDLE:
|
||||
case LIGHT_STATE_IDLE:
|
||||
case LIGHT_STATE_WAITING_FOR_NETWORK:
|
||||
case LIGHT_STATE_IDLE_MAINTENANCE:
|
||||
case LIGHT_STATE_OVERRIDE:
|
||||
assertFalse(mDeviceIdleController.isCharging());
|
||||
assertFalse(mDeviceIdleController.isScreenOn());
|
||||
break;
|
||||
default:
|
||||
fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,9 +83,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Mock
|
||||
Handler mHandler;
|
||||
|
||||
@Mock
|
||||
MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ import org.junit.runners.model.Statement;
|
||||
* Like the following:</p>
|
||||
* <pre class="prettyprint">
|
||||
* @Rule
|
||||
* private final TestableContext mContext = new TestableContext(InstrumentationRegister.getContext());
|
||||
* public final TestableContext mContext = new TestableContext(InstrumentationRegister.getContext());
|
||||
* </pre>
|
||||
*/
|
||||
public class TestableContext extends ContextWrapper implements TestRule {
|
||||
|
||||
Reference in New Issue
Block a user