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:
Kweku Adams
2018-09-28 16:57:09 -07:00
parent 7a96ec0e0a
commit 00e3a37e1a
4 changed files with 684 additions and 37 deletions

View File

@@ -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();

View File

@@ -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.");
}
}
}

View File

@@ -83,9 +83,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
}
}
@Mock
Handler mHandler;
@Mock
MetricsLogger mMetricsLogger = mock(MetricsLogger.class);

View File

@@ -53,7 +53,7 @@ import org.junit.runners.model.Statement;
* Like the following:</p>
* <pre class="prettyprint">
* &#064;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 {