Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68f9a715 authored by Brian Quezada's avatar Brian Quezada Committed by Automerger Merge Worker
Browse files

Merge "Keep screen on when user undims it manually" into sc-qpr1-dev am: 103062f1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15584243

Change-Id: I4c9599ca4017f061e857d5c00f651f4ea6c81309
parents 42f2c92d 103062f1
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -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;
            }
        }
    }
+8 −3
Original line number Diff line number Diff line
@@ -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
+297 −0
Original line number Diff line number Diff line
/*
 * 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<String> 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;
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
    <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
    <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission
        android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>

+305 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading