diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 7555a7f2920bd..c91d8dedc41b3 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -96,6 +96,7 @@ public class Notifier { private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4; private static final int MSG_PROFILE_TIMED_OUT = 5; private static final int MSG_WIRED_CHARGING_STARTED = 6; + private static final int MSG_SCREEN_POLICY = 7; private static final long[] CHARGING_VIBRATION_TIME = { 40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms @@ -120,6 +121,7 @@ public class Notifier { private final SuspendBlocker mSuspendBlocker; private final WindowManagerPolicy mPolicy; private final FaceDownDetector mFaceDownDetector; + private final ScreenUndimDetector mScreenUndimDetector; private final ActivityManagerInternal mActivityManagerInternal; private final InputManagerInternal mInputManagerInternal; private final InputMethodManagerInternal mInputMethodManagerInternal; @@ -167,13 +169,14 @@ public class Notifier { public Notifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { mContext = context; mBatteryStats = batteryStats; mAppOps = mContext.getSystemService(AppOpsManager.class); mSuspendBlocker = suspendBlocker; mPolicy = policy; mFaceDownDetector = faceDownDetector; + mScreenUndimDetector = screenUndimDetector; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); @@ -619,6 +622,22 @@ public class Notifier { mHandler.sendMessage(msg); } + /** + * Called when the screen policy changes. + */ + public void onScreenPolicyUpdate(int newPolicy) { + if (DEBUG) { + Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy); + } + + synchronized (mLock) { + Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY); + msg.arg1 = newPolicy; + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + } + } + /** * Dumps data for bugreports. * @@ -659,6 +678,7 @@ public class Notifier { tm.notifyUserActivity(); mPolicy.userActivity(); mFaceDownDetector.userActivity(event); + mScreenUndimDetector.userActivity(); } void postEnhancedDischargePredictionBroadcast(long delayMs) { @@ -812,6 +832,10 @@ public class Notifier { mSuspendBlocker.release(); } + private void screenPolicyChanging(int screenPolicy) { + mScreenUndimDetector.recordScreenPolicy(screenPolicy); + } + private void lockProfile(@UserIdInt int userId) { mTrustManager.setDeviceLockedForUser(userId, true /*locked*/); } @@ -852,6 +876,9 @@ public class Notifier { case MSG_WIRED_CHARGING_STARTED: showWiredChargingStarted(msg.arg1); break; + case MSG_SCREEN_POLICY: + screenPolicyChanging(msg.arg1); + break; } } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 49d05e0d1cfdf..404f21b88e09c 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -274,6 +274,7 @@ public final class PowerManagerService extends SystemService private final BatterySavingStats mBatterySavingStats; private final AttentionDetector mAttentionDetector; private final FaceDownDetector mFaceDownDetector; + private final ScreenUndimDetector mScreenUndimDetector; private final BinderService mBinderService; private final LocalService mLocalService; private final NativeWrapper mNativeWrapper; @@ -832,9 +833,10 @@ public final class PowerManagerService extends SystemService static class Injector { Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return new Notifier( - looper, context, batteryStats, suspendBlocker, policy, faceDownDetector); + looper, context, batteryStats, suspendBlocker, policy, faceDownDetector, + screenUndimDetector); } SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) { @@ -955,6 +957,7 @@ public final class PowerManagerService extends SystemService mInjector.createAmbientDisplaySuppressionController(context); mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock); mFaceDownDetector = new FaceDownDetector(this::onFlip); + mScreenUndimDetector = new ScreenUndimDetector(); mBatterySavingStats = new BatterySavingStats(mLock); mBatterySaverPolicy = @@ -1141,7 +1144,7 @@ public final class PowerManagerService extends SystemService mBatteryStats = BatteryStatsService.getService(); mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats, mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"), - mPolicy, mFaceDownDetector); + mPolicy, mFaceDownDetector, mScreenUndimDetector); mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager, mInjector.createSuspendBlocker( @@ -1176,6 +1179,7 @@ public final class PowerManagerService extends SystemService mBatterySaverController.systemReady(); mBatterySaverPolicy.systemReady(); mFaceDownDetector.systemReady(mContext); + mScreenUndimDetector.systemReady(mContext); // Register for settings changes. resolver.registerContentObserver(Settings.Secure.getUriFor( @@ -3185,6 +3189,7 @@ public final class PowerManagerService extends SystemService final boolean ready = mDisplayManagerInternal.requestPowerState(groupId, displayPowerRequest, mRequestWaitForNegativeProximity); + mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy); if (DEBUG_SPEW) { Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java new file mode 100644 index 0000000000000..951bc1f76e6d0 --- /dev/null +++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2020 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 android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; +import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.PowerManager; +import android.os.SystemClock; +import android.provider.DeviceConfig; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen + * on temporarily (without changing the screen timeout setting). + */ +public class ScreenUndimDetector { + private static final String TAG = "ScreenUndimDetector"; + private static final boolean DEBUG = false; + + private static final String UNDIM_DETECTOR_WAKE_LOCK = "UndimDetectorWakeLock"; + + /** DeviceConfig flag: is keep screen on feature enabled. */ + static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled"; + private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true; + private static final int OUTCOME_POWER_BUTTON = + FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON; + private static final int OUTCOME_TIMEOUT = + FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__TIMEOUT; + private boolean mKeepScreenOnEnabled; + + /** DeviceConfig flag: how long should we keep the screen on. */ + @VisibleForTesting + static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis"; + @VisibleForTesting + static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10); + private long mKeepScreenOnForMillis; + + /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */ + @VisibleForTesting + static final String KEY_UNDIMS_REQUIRED = "undims_required"; + @VisibleForTesting + static final int DEFAULT_UNDIMS_REQUIRED = 2; + private int mUndimsRequired; + + /** + * DeviceConfig flag: what is the maximum duration between undims to still consider them + * consecutive. + */ + @VisibleForTesting + static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = + "max_duration_between_undims_millis"; + @VisibleForTesting + static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5); + private long mMaxDurationBetweenUndimsMillis; + + @VisibleForTesting + PowerManager.WakeLock mWakeLock; + + @VisibleForTesting + int mCurrentScreenPolicy; + @VisibleForTesting + int mUndimCounter = 0; + @VisibleForTesting + long mUndimCounterStartedMillis; + private long mUndimOccurredTime = -1; + private long mInteractionAfterUndimTime = -1; + private InternalClock mClock; + + public ScreenUndimDetector() { + mClock = new InternalClock(); + } + + ScreenUndimDetector(InternalClock clock) { + mClock = clock; + } + + static class InternalClock { + public long getCurrentTime() { + return SystemClock.elapsedRealtime(); + } + } + + /** Should be called in parent's systemReady() */ + public void systemReady(Context context) { + readValuesFromDeviceConfig(); + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE, + context.getMainExecutor(), + (properties) -> onDeviceConfigChange(properties.getKeyset())); + + final PowerManager powerManager = context.getSystemService(PowerManager.class); + mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK + | PowerManager.ON_AFTER_RELEASE, + UNDIM_DETECTOR_WAKE_LOCK); + } + + /** + * Launches a message that figures out the screen transitions and detects user undims. Must be + * called by the parent that is trying to update the screen policy. + */ + public void recordScreenPolicy(int newPolicy) { + if (newPolicy == mCurrentScreenPolicy) { + return; + } + + if (DEBUG) { + Slog.d(TAG, + "Screen policy transition: " + mCurrentScreenPolicy + " -> " + newPolicy); + } + + // update the current policy with the new one immediately so we don't accidentally get + // into a loop (which is possible if the switch below triggers a new policy). + final int currentPolicy = mCurrentScreenPolicy; + mCurrentScreenPolicy = newPolicy; + + if (!mKeepScreenOnEnabled) { + return; + } + + switch (currentPolicy) { + case POLICY_DIM: + if (newPolicy == POLICY_BRIGHT) { + final long now = mClock.getCurrentTime(); + final long timeElapsedSinceFirstUndim = now - mUndimCounterStartedMillis; + if (timeElapsedSinceFirstUndim >= mMaxDurationBetweenUndimsMillis) { + reset(); + } + if (mUndimCounter == 0) { + mUndimCounterStartedMillis = now; + } + + mUndimCounter++; + + if (DEBUG) { + Slog.d(TAG, "User undim, counter=" + mUndimCounter + + " (required=" + mUndimsRequired + ")" + + ", timeElapsedSinceFirstUndim=" + timeElapsedSinceFirstUndim + + " (max=" + mMaxDurationBetweenUndimsMillis + ")"); + } + if (mUndimCounter >= mUndimsRequired) { + reset(); + if (DEBUG) { + Slog.d(TAG, "Acquiring a wake lock for " + mKeepScreenOnForMillis); + } + if (mWakeLock != null) { + mUndimOccurredTime = mClock.getCurrentTime(); + mWakeLock.acquire(mKeepScreenOnForMillis); + } + } + } else { + if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) { + checkAndLogUndim(OUTCOME_TIMEOUT); + } + reset(); + } + break; + case POLICY_BRIGHT: + if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) { + checkAndLogUndim(OUTCOME_POWER_BUTTON); + } + if (newPolicy != POLICY_DIM) { + reset(); + } + break; + } + } + + @VisibleForTesting + void reset() { + if (DEBUG) { + Slog.d(TAG, "Resetting the undim detector"); + } + mUndimCounter = 0; + mUndimCounterStartedMillis = 0; + if (mWakeLock != null && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + + private boolean readKeepScreenOnNotificationEnabled() { + return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_ENABLED, + DEFAULT_KEEP_SCREEN_ON_ENABLED); + } + + private long readKeepScreenOnForMillis() { + return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_FOR_MILLIS, + DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS); + } + + private int readUndimsRequired() { + int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + DEFAULT_UNDIMS_REQUIRED); + + if (undimsRequired < 1 || undimsRequired > 5) { + Slog.e(TAG, "Provided undimsRequired=" + undimsRequired + + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED); + return DEFAULT_UNDIMS_REQUIRED; + } + + return undimsRequired; + } + + private long readMaxDurationBetweenUndimsMillis() { + return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS, + DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS); + } + + private void onDeviceConfigChange(@NonNull Set keys) { + for (String key : keys) { + Slog.i(TAG, "onDeviceConfigChange; key=" + key); + switch (key) { + case KEY_KEEP_SCREEN_ON_ENABLED: + case KEY_KEEP_SCREEN_ON_FOR_MILLIS: + case KEY_UNDIMS_REQUIRED: + case KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS: + readValuesFromDeviceConfig(); + return; + default: + Slog.i(TAG, "Ignoring change on " + key); + } + } + } + + @VisibleForTesting + void readValuesFromDeviceConfig() { + mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled(); + mKeepScreenOnForMillis = readKeepScreenOnForMillis(); + mUndimsRequired = readUndimsRequired(); + mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis(); + + Slog.i(TAG, "readValuesFromDeviceConfig():" + + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis + + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled + + "\nmUndimsRequired=" + mUndimsRequired); + + } + + /** + * The user interacted with the screen after an undim, indicating the phone is in use. + * We use this event for logging. + */ + public void userActivity() { + if (mUndimOccurredTime != 1 && mInteractionAfterUndimTime == -1) { + mInteractionAfterUndimTime = mClock.getCurrentTime(); + } + } + + /** + * Checks and logs if an undim occurred. + * + * A log will occur if an undim seems to have resulted in a timeout or a direct screen off such + * as from a power button. Some outcomes may not be correctly assigned to a + * TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME value. + */ + private void checkAndLogUndim(int outcome) { + if (mUndimOccurredTime != -1) { + long now = mClock.getCurrentTime(); + FrameworkStatsLog.write(FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED, + outcome, + /* time_to_outcome_millis=*/ now - mUndimOccurredTime, + /* time_to_first_interaction_millis= */ + mInteractionAfterUndimTime != -1 ? now - mInteractionAfterUndimTime : -1 + ); + mUndimOccurredTime = -1; + mInteractionAfterUndimTime = -1; + } + } +} diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index 17a5dccb57da9..3cab5ecd3de16 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -28,6 +28,7 @@ + diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java new file mode 100644 index 0000000000000..f94377fe51c23 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2020 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 android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR; +import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; + +import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS; +import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED; +import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS; +import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.SystemClock; +import android.provider.DeviceConfig; +import android.testing.TestableContext; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.server.testables.TestableDeviceConfig; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +/** + * Tests for {@link com.android.server.power.ScreenUndimDetector} + */ +@RunWith(JUnit4.class) +public class ScreenUndimDetectorTest { + private static final List ALL_POLICIES = + Arrays.asList(POLICY_OFF, + POLICY_DOZE, + POLICY_DIM, + POLICY_BRIGHT, + POLICY_VR); + + @ClassRule + public static final TestableContext sContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getTargetContext(), null); + @Rule + public TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); + + private ScreenUndimDetector mScreenUndimDetector; + + private final TestClock mClock = new TestClock(); + + private static class TestClock extends ScreenUndimDetector.InternalClock { + long mCurrentTime = 0; + @Override + public long getCurrentTime() { + return mCurrentTime; + } + + public void advanceTime(long millisAdvanced) { + mCurrentTime += millisAdvanced; + } + } + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(1), false /*makeDefault*/); + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS, + Long.toString(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS), + false /*makeDefault*/); + + mScreenUndimDetector = new ScreenUndimDetector(mClock); + mScreenUndimDetector.systemReady(sContext); + } + + @Test + public void recordScreenPolicy_disabledByFlag_noop() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/); + + setup(); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + + @Test + public void recordScreenPolicy_samePolicy_noop() { + for (int policy : ALL_POLICIES) { + setup(); + mScreenUndimDetector.recordScreenPolicy(policy); + mScreenUndimDetector.recordScreenPolicy(policy); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + } + + @Test + public void recordScreenPolicy_dimToBright_extends() { + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue(); + } + + @Test + public void recordScreenPolicy_otherTransitions_doesNotExtend() { + for (int from : ALL_POLICIES) { + for (int to : ALL_POLICIES) { + if (from == POLICY_DIM && to == POLICY_BRIGHT) { + continue; + } + setup(); + mScreenUndimDetector.recordScreenPolicy(from); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + } + } + + @Test + public void recordScreenPolicy_dimToBright_twoUndimsNeeded_extends() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue(); + } + + @Test + public void recordScreenPolicy_dimBrightDimOff_resetsCounter_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + + @Test + public void recordScreenPolicy_undimToOff_resetsCounter() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + } + + @Test + public void recordScreenPolicy_undimOffUndim_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + // undim + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + // off + mScreenUndimDetector.recordScreenPolicy(POLICY_OFF); + // second undim + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1); + } + + @Test + public void recordScreenPolicy_dimToBright_tooFarApart_doesNotExtend() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(2), false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + mClock.advanceTime(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS + 5); + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1); + } + + @Test + public void recordScreenPolicy_dimToNonBright_resets() { + for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) { + setup(); + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = 123; + mScreenUndimDetector.mWakeLock.acquire(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_DIM); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0); + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + + } + + @Test + public void recordScreenPolicy_brightToNonDim_resets() { + for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) { + setup(); + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = 123; + mScreenUndimDetector.mWakeLock.acquire(); + + mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0); + assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse(); + } + } + + @Test + public void recordScreenPolicy_otherTransitions_doesNotReset() { + DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, + KEY_UNDIMS_REQUIRED, + Integer.toString(3), + false /*makeDefault*/); + mScreenUndimDetector.readValuesFromDeviceConfig(); + + for (int from : ALL_POLICIES) { + for (int to : ALL_POLICIES) { + if (from == POLICY_DIM && to != POLICY_BRIGHT) { + continue; + } + if (from == POLICY_BRIGHT && to != POLICY_DIM) { + continue; + } + mScreenUndimDetector.mCurrentScreenPolicy = POLICY_OFF; + mScreenUndimDetector.mUndimCounter = 1; + mScreenUndimDetector.mUndimCounterStartedMillis = + SystemClock.currentThreadTimeMillis(); + + mScreenUndimDetector.recordScreenPolicy(from); + mScreenUndimDetector.recordScreenPolicy(to); + + assertThat(mScreenUndimDetector.mUndimCounter).isNotEqualTo(0); + assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isNotEqualTo(0); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java index 5012ca9ab420e..6e3f754e48825 100644 --- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java @@ -210,7 +210,7 @@ public class NotifierTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return mNotifierMock; } @@ -298,6 +298,7 @@ public class NotifierTest { BatteryStats.SERVICE_NAME)), mInjector.createSuspendBlocker(mService, "testBlocker"), null, + null, null); } } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 5eabc1bea1484..3d64d4b5abb93 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -215,7 +215,7 @@ public class PowerManagerServiceTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { return mNotifierMock; }