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

Commit 1ae6cf91 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Initial sleep-lock-screen implementation

We're now listening for sleep events and forcing the device into
sleep mode when necessary.

Display state is now cached and handled properly for cases where
the device wakes up and should go back to sleep.

Test: atest LockScreenWakeUpControllerTest
Test: manual
Bug: 111414690
Bug: 111405682
Fixes: 120864496
Change-Id: I3096329e8f6a07a686582d35c4b0e9977bf9ab1b
parent 66f04be1
Loading
Loading
Loading
Loading
+23 −17
Original line number Diff line number Diff line
@@ -11,13 +11,12 @@
 * 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
 * limitations under the License.
 */

package com.android.systemui.plugins;

import android.hardware.Sensor;
import android.hardware.TriggerEventListener;
import android.hardware.SensorListener;

import com.android.systemui.plugins.annotations.ProvidesInterface;

@@ -31,26 +30,30 @@ public interface SensorManagerPlugin extends Plugin {
    int VERSION = 1;

    /**
     * Registers for trigger events from the sensor. Trigger events are one-shot and need to
     * re-registered in order for them to be fired again.
     * Registers for sensor events. Events will be sent until the listener is unregistered.
     * @param sensor
     * @param listener
     * @see android.hardware.SensorManager#requestTriggerSensor(
     *     android.hardware.TriggerEventListener, android.hardware.Sensor)
     * @see android.hardware.SensorManager#registerListener(SensorListener, int)
     */
    void registerTriggerEvent(Sensor sensor, TriggerEventListener listener);
    void registerListener(Sensor sensor, SensorEventListener listener);

    /**
     * Unregisters trigger events from the sensor.
     * Unregisters events from the sensor.
     * @param sensor
     * @param listener
     */
    void unregisterTriggerEvent(Sensor sensor, TriggerEventListener listener);
    void unregisterListener(Sensor sensor, SensorEventListener listener);

    interface TriggerEventListener {
        void onTrigger(TriggerEvent event);
    /**
     * Listener triggered whenever the Sensor has new data.
     */
    interface SensorEventListener {
        void onSensorChanged(SensorEvent event);
    }

    /**
     * Sensor that can be defined in a plugin.
     */
    class Sensor {
        public static final int TYPE_WAKE_LOCK_SCREEN = 1;
        public static final int TYPE_WAKE_DISPLAY = 2;
@@ -67,29 +70,32 @@ public interface SensorManagerPlugin extends Plugin {
        }
    }

    class TriggerEvent {
    /**
     * Event sent by a {@link Sensor}.
     */
    class SensorEvent {
        Sensor mSensor;
        int mVendorType;
        float[] mValues;

        /**
         * Creates a trigger event
         * Creates a sensor event.
         * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
         * @param vendorType The vendor type, which should be unique for each type of sensor,
         *                   e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
         */
        public TriggerEvent(Sensor sensor, int vendorType) {
        public SensorEvent(Sensor sensor, int vendorType) {
            this(sensor, vendorType, null);
        }

        /**
         * Creates a trigger event
         * Creates a sensor event.
         * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
         * @param vendorType The vendor type, which should be unique for each type of sensor,
         *                   e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
         * @param values Values captured by the sensor.
         */
        public TriggerEvent(Sensor sensor, int vendorType, float[] values) {
        public SensorEvent(Sensor sensor, int vendorType, float[] values) {
            mSensor = sensor;
            mVendorType = vendorType;
            mValues = values;
+1 −3
Original line number Diff line number Diff line
@@ -44,8 +44,7 @@ public class DozeLog {
    public static final int PULSE_REASON_SENSOR_PICKUP = 3;
    public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
    public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 6;
    public static final int REASON_SENSOR_WAKE_UP = 7;
    public static final int REASON_SENSOR_WAKE_UP = 6;

    private static boolean sRegisterKeyguardCallback = true;

@@ -212,7 +211,6 @@ public class DozeLog {
            case PULSE_REASON_SENSOR_PICKUP: return "pickup";
            case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
            case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakeLockScreen";
            case REASON_SENSOR_WAKE_UP: return "wakeup";
            default: throw new IllegalArgumentException("bad reason: " + pulseReason);
        }
+12 −25
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.doze;

import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;

import android.annotation.AnyThread;
import android.app.ActivityManager;
@@ -26,7 +25,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
@@ -114,14 +112,7 @@ public class DozeSensors {
                        DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
                        true /* reports touch coordinates */,
                        true /* touchscreen */),
                new PluginTriggerSensor(
                        new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
                        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
                        true /* configured */,
                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
                        false /* reports touch coordinates */,
                        false /* touchscreen */),
                new PluginTriggerSensor(
                new PluginSensor(
                        new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                        Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
                        true /* configured */,
@@ -272,7 +263,7 @@ public class DozeSensors {
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
        public void onSensorChanged(android.hardware.SensorEvent event) {
            if (DEBUG) Log.d(TAG, "onSensorChanged " + event);

            mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
@@ -417,7 +408,7 @@ public class DozeSensors {

        protected String triggerEventToString(TriggerEvent event) {
            if (event == null) return null;
            final StringBuilder sb = new StringBuilder("TriggerEvent[")
            final StringBuilder sb = new StringBuilder("SensorEvent[")
                    .append(event.timestamp).append(',')
                    .append(event.sensor.getName());
            if (event.values != null) {
@@ -432,23 +423,19 @@ public class DozeSensors {
    /**
     * A Sensor that is injected via plugin.
     */
    private class PluginTriggerSensor extends TriggerSensor {
    private class PluginSensor extends TriggerSensor {

        private final SensorManagerPlugin.Sensor mPluginSensor;
        private final SensorManagerPlugin.TriggerEventListener mTriggerEventListener = (event) -> {
        private final SensorManagerPlugin.SensorEventListener mTriggerEventListener = (event) -> {
            DozeLog.traceSensor(mContext, mPulseReason);
            mHandler.post(mWakeLock.wrap(() -> {
                if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
                mRegistered = false;
                if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
                mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
                        event.getValues());
                if (!mRegistered) {
                    updateListener();  // reregister, this sensor only fires once
                }
            }));
        };

        PluginTriggerSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
        PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
                int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
            super(null, setting, configured, pulseReason, reportsTouchCoordinates,
                    requiresTouchscreen);
@@ -460,13 +447,13 @@ public class DozeSensors {
            if (!mConfigured) return;
            AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
                asyncSensorManager.requestPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
                asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener);
                mRegistered = true;
                if (DEBUG) Log.d(TAG, "requestPluginTriggerSensor");
                if (DEBUG) Log.d(TAG, "registerPluginListener");
            } else if (mRegistered) {
                asyncSensorManager.cancelPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
                asyncSensorManager.unregisterPluginListener(mPluginSensor, mTriggerEventListener);
                mRegistered = false;
                if (DEBUG) Log.d(TAG, "cancelPluginTriggerSensor");
                if (DEBUG) Log.d(TAG, "unregisterPluginListener");
            }
        }

@@ -479,7 +466,7 @@ public class DozeSensors {
                    .append(", mSensor=").append(mPluginSensor).append("}").toString();
        }

        private String triggerEventToString(SensorManagerPlugin.TriggerEvent event) {
        private String triggerEventToString(SensorManagerPlugin.SensorEvent event) {
            if (event == null) return null;
            final StringBuilder sb = new StringBuilder("PluginTriggerEvent[")
                    .append(event.getSensor()).append(',')
+10 −9
Original line number Diff line number Diff line
@@ -53,6 +53,12 @@ public class DozeTriggers implements DozeMachine.Part {
    /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
    private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";

    /**
     * Last value sent by the wake-display sensor.
     * Assuming that the screen should start on.
     */
    private static boolean sWakeDisplaySensorState = true;

    private final Context mContext;
    private final DozeMachine mMachine;
    private final DozeSensors mDozeSensors;
@@ -128,7 +134,6 @@ public class DozeTriggers implements DozeMachine.Part {
        boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
        boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
        boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
        boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
        boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;

@@ -145,14 +150,6 @@ public class DozeTriggers implements DozeMachine.Part {
                if (isDoubleTap) {
                    mDozeHost.onDoubleTap(screenX, screenY);
                    mMachine.wakeUp();
                } else if (isWakeLockScreen) {
                    if (wakeEvent) {
                        mDozeHost.setPassiveInterrupt(true);
                        mMachine.wakeUp();
                        DozeLog.traceLockScreenWakeUp(wakeEvent);
                    } else {
                        if (DEBUG) Log.d(TAG, "Unpulsing");
                    }
                } else if (isPickup) {
                    mDozeHost.setPassiveInterrupt(true);
                    mMachine.wakeUp();
@@ -199,6 +196,7 @@ public class DozeTriggers implements DozeMachine.Part {
        DozeMachine.State state = mMachine.getState();
        boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
        boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
        sWakeDisplaySensorState = wake;

        if (wake) {
            proximityCheckThenCall((result) -> {
@@ -234,6 +232,9 @@ public class DozeTriggers implements DozeMachine.Part {
                }
                mDozeSensors.setListening(true);
                mDozeHost.setPassiveInterrupt(false);
                if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
                    onWakeScreen(false);
                }
                break;
            case DOZE_AOD_PAUSED:
            case DOZE_AOD_PAUSING:
+121 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.doze;

import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.util.AsyncSensorManager;

/**
 * Controller responsible for waking up or making the device sleep based on ambient sensors.
 */
public class LockScreenWakeUpController implements StatusBarStateController.StateListener,
        SensorManagerPlugin.SensorEventListener {

    private static final String TAG = LockScreenWakeUpController.class.getSimpleName();
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private final AsyncSensorManager mAsyncSensorManager;
    private final SensorManagerPlugin.Sensor mSensor;
    private final AmbientDisplayConfiguration mAmbientConfiguration;
    private final PowerManager mPowerManager;
    private final DozeHost mDozeHost;
    private final Handler mHandler;
    private boolean mRegistered;
    private boolean mDozing;

    public LockScreenWakeUpController(Context context, DozeHost dozeHost) {
        this(Dependency.get(AsyncSensorManager.class),
                new SensorManagerPlugin.Sensor(SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN),
                new AmbientDisplayConfiguration(context),
                context.getSystemService(PowerManager.class),
                dozeHost, Dependency.get(StatusBarStateController.class), new Handler());
    }

    @VisibleForTesting
    public LockScreenWakeUpController(AsyncSensorManager asyncSensorManager,
            SensorManagerPlugin.Sensor sensor, AmbientDisplayConfiguration ambientConfiguration,
            PowerManager powerManager, DozeHost dozeHost,
            StatusBarStateController statusBarStateController, Handler handler) {
        mAsyncSensorManager = asyncSensorManager;
        mSensor = sensor;
        mAmbientConfiguration = ambientConfiguration;
        mPowerManager = powerManager;
        mDozeHost = dozeHost;
        mHandler = handler;
        statusBarStateController.addCallback(this);
    }

    @Override
    public void onStateChanged(int newState) {
        boolean isLockScreen = newState == StatusBarState.KEYGUARD
                || newState == StatusBarState.SHADE_LOCKED;

        if (!mAmbientConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)) {
            if (mRegistered) {
                mAsyncSensorManager.unregisterPluginListener(mSensor, this);
                mRegistered = false;
            }
            return;
        }

        if (isLockScreen && !mRegistered) {
            mAsyncSensorManager.registerPluginListener(mSensor, this);
            mRegistered = true;
        } else if (!isLockScreen && mRegistered) {
            mAsyncSensorManager.unregisterPluginListener(mSensor, this);
            mRegistered = false;
        }
    }

    @Override
    public void onDozingChanged(boolean isDozing) {
        mDozing = isDozing;
    }

    @Override
    public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
        mHandler.post(()-> {
            float[] rawValues = event.getValues();
            boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;

            DozeLog.traceLockScreenWakeUp(wakeEvent);
            if (wakeEvent && mDozing) {
                mDozeHost.setPassiveInterrupt(true);
                if (DEBUG) Log.d(TAG, "Wake up.");
                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
            } else if (!wakeEvent && !mDozing) {
                if (DEBUG) Log.d(TAG, "Nap time.");
                mPowerManager.goToSleep(SystemClock.uptimeMillis(),
                        PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
            } else if (DEBUG) {
                Log.d(TAG, "Skip sensor event. Wake? " + wakeEvent + " dozing: " + mDozing);
            }
        });
    }
}
Loading