summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java173
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java543
-rw-r--r--services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java3
-rw-r--r--tests/testables/src/android/testing/TestableContext.java2
4 files changed, 684 insertions, 37 deletions
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index a34c2b93e3bf..6cba76424e6d 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -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();
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
new file mode 100644
index 000000000000..66650700f599
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -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.");
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 54ac6fc7db93..bd4a356fcb5c 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -84,9 +84,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
}
@Mock
- Handler mHandler;
-
- @Mock
MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
private BatterySaverPolicyForTest mBatterySaverPolicy;
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index cf84c7926549..fff9635992d4 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -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 {