Merge "Treat changes in device-state as user-activity."
This commit is contained in:
committed by
Android (Google) Code Review
commit
85949672f2
@@ -334,6 +334,12 @@ public final class PowerManager {
|
||||
*/
|
||||
public static final int USER_ACTIVITY_EVENT_FACE_DOWN = 5;
|
||||
|
||||
/**
|
||||
* User activity event type: There is a change in the device state.
|
||||
* @hide
|
||||
*/
|
||||
public static final int USER_ACTIVITY_EVENT_DEVICE_STATE = 6;
|
||||
|
||||
/**
|
||||
* User activity flag: If already dimmed, extend the dim timeout
|
||||
* but do not brighten. This flag is useful for keeping the screen on
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.SystemSensorManager;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
|
||||
@@ -60,6 +61,7 @@ import android.os.BatteryManagerInternal;
|
||||
import android.os.BatterySaverPolicyConfig;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.IBinder;
|
||||
import android.os.IPowerManager;
|
||||
import android.os.Looper;
|
||||
@@ -1151,6 +1153,9 @@ public final class PowerManagerService extends SystemService
|
||||
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
|
||||
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
|
||||
}
|
||||
|
||||
mContext.getSystemService(DeviceStateManager.class).registerCallback(
|
||||
new HandlerExecutor(mHandler), new DeviceStateListener());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6349,4 +6354,25 @@ public final class PowerManagerService extends SystemService
|
||||
return interceptPowerKeyDownInternal(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens to changes in device state and updates the interactivity time.
|
||||
* Any changes to the device state are treated as user interactions.
|
||||
*/
|
||||
class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
|
||||
private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
|
||||
|
||||
@Override
|
||||
public void onStateChanged(int deviceState) {
|
||||
if (mDeviceState != deviceState) {
|
||||
mDeviceState = deviceState;
|
||||
// Device-state interactions are applied to the default display so that they
|
||||
// are reflected only with the default power group.
|
||||
userActivityInternal(Display.DEFAULT_DISPLAY, mClock.uptimeMillis(),
|
||||
PowerManager.USER_ACTIVITY_EVENT_DEVICE_STATE, /* flags= */0,
|
||||
Process.SYSTEM_UID);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -40,26 +40,26 @@ android_test {
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"androidx.test.core",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.ext.truth",
|
||||
"frameworks-base-testutils",
|
||||
"hamcrest-library",
|
||||
"kotlin-test",
|
||||
"mockingservicestests-utils-mockito",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"service-blobstore",
|
||||
"service-jobscheduler",
|
||||
"service-permission.impl",
|
||||
"services.core",
|
||||
"services.devicepolicy",
|
||||
"services.net",
|
||||
"services.usage",
|
||||
"service-jobscheduler",
|
||||
"service-permission.impl",
|
||||
"service-blobstore",
|
||||
"androidx.test.core",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.ext.truth",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"truth-prebuilt",
|
||||
"hamcrest-library",
|
||||
"servicestests-utils-mockito-extended",
|
||||
"mockingservicestests-utils-mockito",
|
||||
"servicestests-core-utils",
|
||||
"servicestests-utils-mockito-extended",
|
||||
"testables",
|
||||
"kotlin-test",
|
||||
"truth-prebuilt",
|
||||
// TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
|
||||
"testng",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.power;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.attention.AttentionManagerInternal;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.os.BatteryManagerInternal;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerSaveState;
|
||||
import android.os.test.TestLooper;
|
||||
import android.provider.Settings;
|
||||
import android.service.dreams.DreamManagerInternal;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.lights.LightsManager;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
import com.android.server.power.PowerManagerService.BatteryReceiver;
|
||||
import com.android.server.power.PowerManagerService.Injector;
|
||||
import com.android.server.power.PowerManagerService.NativeWrapper;
|
||||
import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
|
||||
import com.android.server.power.batterysaver.BatterySaverController;
|
||||
import com.android.server.power.batterysaver.BatterySaverPolicy;
|
||||
import com.android.server.power.batterysaver.BatterySaverStateMachine;
|
||||
import com.android.server.power.batterysaver.BatterySavingStats;
|
||||
import com.android.server.testutils.OffsettableClock;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Tests for {@link com.android.server.power.PowerManagerService}.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksServicesTests:PowerManagerServiceMockingTest
|
||||
*/
|
||||
public class PowerManagerServiceMockingTest {
|
||||
private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
|
||||
private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
|
||||
|
||||
private static final float BRIGHTNESS_FACTOR = 0.7f;
|
||||
private static final boolean BATTERY_SAVER_ENABLED = true;
|
||||
|
||||
@Mock private BatterySaverController mBatterySaverControllerMock;
|
||||
@Mock private BatterySaverPolicy mBatterySaverPolicyMock;
|
||||
@Mock private BatterySaverStateMachine mBatterySaverStateMachineMock;
|
||||
@Mock private LightsManager mLightsManagerMock;
|
||||
@Mock private DisplayManagerInternal mDisplayManagerInternalMock;
|
||||
@Mock private BatteryManagerInternal mBatteryManagerInternalMock;
|
||||
@Mock private ActivityManagerInternal mActivityManagerInternalMock;
|
||||
@Mock private AttentionManagerInternal mAttentionManagerInternalMock;
|
||||
@Mock private DreamManagerInternal mDreamManagerInternalMock;
|
||||
@Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
|
||||
@Mock private Notifier mNotifierMock;
|
||||
@Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
|
||||
@Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
|
||||
@Mock private SystemPropertiesWrapper mSystemPropertiesMock;
|
||||
@Mock private DeviceStateManager mDeviceStateManagerMock;
|
||||
|
||||
@Mock
|
||||
private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
|
||||
|
||||
private PowerManagerService mService;
|
||||
private PowerSaveState mPowerSaveState;
|
||||
private ContextWrapper mContextSpy;
|
||||
private BatteryReceiver mBatteryReceiver;
|
||||
private UserSwitchedReceiver mUserSwitchedReceiver;
|
||||
private Resources mResourcesSpy;
|
||||
private OffsettableClock mClock;
|
||||
private TestLooper mTestLooper;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
|
||||
mPowerSaveState = new PowerSaveState.Builder()
|
||||
.setBatterySaverEnabled(BATTERY_SAVER_ENABLED)
|
||||
.setBrightnessFactor(BRIGHTNESS_FACTOR)
|
||||
.build();
|
||||
when(mBatterySaverPolicyMock.getBatterySaverPolicy(
|
||||
eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS)))
|
||||
.thenReturn(mPowerSaveState);
|
||||
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
|
||||
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
|
||||
when(mDisplayManagerInternalMock.requestPowerState(anyInt(), any(), anyBoolean()))
|
||||
.thenReturn(true);
|
||||
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
|
||||
when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
|
||||
|
||||
addLocalServiceMock(LightsManager.class, mLightsManagerMock);
|
||||
addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
|
||||
addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock);
|
||||
addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
|
||||
addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock);
|
||||
addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternalMock);
|
||||
|
||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||
mResourcesSpy = spy(mContextSpy.getResources());
|
||||
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
|
||||
|
||||
MockContentResolver cr = new MockContentResolver(mContextSpy);
|
||||
cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
when(mContextSpy.getContentResolver()).thenReturn(cr);
|
||||
|
||||
when(mContextSpy.getSystemService(DeviceStateManager.class))
|
||||
.thenReturn(mDeviceStateManagerMock);
|
||||
|
||||
Settings.Global.putInt(mContextSpy.getContentResolver(),
|
||||
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
|
||||
|
||||
mClock = new OffsettableClock.Stopped();
|
||||
mTestLooper = new TestLooper(mClock::now);
|
||||
}
|
||||
|
||||
private PowerManagerService createService() {
|
||||
mService = new PowerManagerService(mContextSpy, new Injector() {
|
||||
@Override
|
||||
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
|
||||
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
|
||||
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
|
||||
return mNotifierMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
|
||||
return super.createSuspendBlocker(service, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
BatterySaverPolicy createBatterySaverPolicy(
|
||||
Object lock, Context context, BatterySavingStats batterySavingStats) {
|
||||
return mBatterySaverPolicyMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
BatterySaverController createBatterySaverController(
|
||||
Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
|
||||
BatterySavingStats batterySavingStats) {
|
||||
return mBatterySaverControllerMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
BatterySaverStateMachine createBatterySaverStateMachine(Object lock, Context context,
|
||||
BatterySaverController batterySaverController) {
|
||||
return mBatterySaverStateMachineMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
NativeWrapper createNativeWrapper() {
|
||||
return mNativeWrapperMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
WirelessChargerDetector createWirelessChargerDetector(
|
||||
SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
|
||||
return mWirelessChargerDetectorMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
|
||||
return mAmbientDisplayConfigurationMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
InattentiveSleepWarningController createInattentiveSleepWarningController() {
|
||||
return mInattentiveSleepWarningControllerMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemPropertiesWrapper createSystemPropertiesWrapper() {
|
||||
return mSystemPropertiesMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
PowerManagerService.Clock createClock() {
|
||||
return () -> mClock.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
Handler createHandler(Looper looper, Handler.Callback callback) {
|
||||
return new Handler(mTestLooper.getLooper(), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
void invalidateIsInteractiveCaches() {
|
||||
// Avoids an SELinux failure.
|
||||
}
|
||||
});
|
||||
return mService;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
LocalServices.removeServiceForTest(LightsManager.class);
|
||||
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(BatteryManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(AttentionManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(DreamManagerInternal.class);
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock and registers it to {@link LocalServices}.
|
||||
*/
|
||||
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
|
||||
LocalServices.removeServiceForTest(clazz);
|
||||
LocalServices.addService(clazz, mock);
|
||||
}
|
||||
|
||||
private void advanceTime(long timeMs) {
|
||||
mClock.fastForward(timeMs);
|
||||
mTestLooper.dispatchAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserActivityOnDeviceStateChange() {
|
||||
createService();
|
||||
mService.systemReady(null);
|
||||
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
||||
|
||||
final DisplayInfo info = new DisplayInfo();
|
||||
info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
|
||||
when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);
|
||||
|
||||
final ArgumentCaptor<DeviceStateCallback> deviceStateCallbackCaptor =
|
||||
ArgumentCaptor.forClass(DeviceStateCallback.class);
|
||||
verify(mDeviceStateManagerMock).registerCallback(any(),
|
||||
deviceStateCallbackCaptor.capture());
|
||||
|
||||
// Advance the time 10001 and verify that the device thinks it has been idle
|
||||
// for just less than that.
|
||||
mService.onUserActivity();
|
||||
advanceTime(10001);
|
||||
assertThat(mService.wasDeviceIdleForInternal(10000)).isTrue();
|
||||
|
||||
// Send a display state change event and advance the clock 10.
|
||||
final DeviceStateCallback deviceStateCallback = deviceStateCallbackCaptor.getValue();
|
||||
deviceStateCallback.onStateChanged(1);
|
||||
final long timeToAdvance = 10;
|
||||
advanceTime(timeToAdvance);
|
||||
|
||||
// Ensure that the device has been idle for only 10 (doesn't include the idle time
|
||||
// before the display state event).
|
||||
assertThat(mService.wasDeviceIdleForInternal(timeToAdvance - 1)).isTrue();
|
||||
assertThat(mService.wasDeviceIdleForInternal(timeToAdvance)).isFalse();
|
||||
|
||||
// Send the same state and ensure that does not trigger an update.
|
||||
deviceStateCallback.onStateChanged(1);
|
||||
advanceTime(timeToAdvance);
|
||||
final long newTime = timeToAdvance * 2;
|
||||
|
||||
assertThat(mService.wasDeviceIdleForInternal(newTime - 1)).isTrue();
|
||||
assertThat(mService.wasDeviceIdleForInternal(newTime)).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user