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

Commit 65501d90 authored by Bruno Martins's avatar Bruno Martins Committed by Sam Mortimer
Browse files

PowerManager: Add proximity check on wake

This is a squash of the following commits, forward-ported to Oreo
and adapted to the Lineage SDK:

Author: Danesh M <daneshm90@gmail.com>
Date:   Wed Jun 25 21:31:49 2014 -0700

    ProximityWake : Add support for checking proximity when waking device

    Change-Id: Ia5ff446d88435773acccc7467e66009000dc20cb

Author: Schubi <schubi@erlangen.ccc.de>
Date:   Tue Jul 29 02:10:16 2014 +0200

    Be sure to shutdown the proximity sensor after display wake

    This fixes:
    http://review.cyanogenmod.org/#/c/66657/



    Change-Id: I1768f13cb48c3e056d0e137642690fc3d650c4ab

Author: Danesh M <daneshm90@gmail.com>
Date:   Mon Aug 4 20:18:18 2014 -0700

    PowerManager : Make proximity check opt-in

    Change-Id: I7cf64a82530da2e655018e43683ba7a5584d54f8

Author: Danesh M <daneshm90@gmail.com>
Date:   Fri Jul 25 19:02:26 2014 -0700

    Framework : Fix proximity wakeup reference

    Change-Id: Ia40ca6fbf6e37fbb3996f2384f725c30b88c2131

Author: dankoman <dankoman30@gmail.com>
Date:   Thu Feb 5 15:12:13 2015 +0100

    [1/2] Frameworks: let InCallUI handle proximity sensor for incoming calls

    Fixes "while 'prevent accidental wake-up' is on, proximity sensor
    doesn't control screen state on incoming call. Must manually
    turn on screen to see who's calling."

    Change-Id: I738b3bbd328992c8a8010a0c8d9aa1e444cfa9f9

Author: Steve Kondik <steve@cyngn.com>
Date:   Thu May 21 13:10:54 2015 -0700

    power: Fix locking for wakeup proximity check

     * Often I'm noticing high power consumption due to the proximity sensor
       never turning off. Add synchronization around this code to ensure
       ordering.

    Change-Id: I8ccf3152166cd896e0ce2551c01b8ac8f501d782

Author: Scott Mertz <scott@cyngn.com>
Date:   Fri Aug 21 13:47:51 2015 -0700

    add config for proximity check on screen on default value

    Change-Id: I7e6ae08e23ee147a37986aa6aa9b3176b301a09e

Author: Danesh M <daneshm90@gmail.com>
Date:   Mon Aug 4 18:09:06 2014 -0700

    Services : Ensure proximity check is taken into consideration

    Only do the proximity check if explicitly being asked to do so.
    This is a patch that was never ported from cm-11.0 :
    2293e60c

    issue-id: CYNGNOS-1223

    Change-Id: Id1be619e638de6a45252d8390eab6e38bd5de5a7

Author: Erica Chang <echang@cyngn.com>
Date:   Tue Jun 9 15:01:12 2015 -0700

    services: button brightness should check proximity

    Change-Id: I10a72fa6d8b520e86cfef3d7ded489fd7fa936d2

Author: Steve Kondik <steve@cyngn.com>
Date:   Mon Oct 26 03:07:26 2015 -0700

    powermanager: Initialize SensorManager in systemReady()

     * Service startup ordering is different on M and the sensor service
       is not ready during construction of the PowerManager. This was
       causing a hang on boot. Move it to systemReady instead.

    Change-Id: I9e0293484e1aaaf9f82f9c75680bec558607c54d

Author: Adnan Begovic <adnan@cyngn.com>
Date:   Mon Nov 9 17:59:13 2015 -0800

    fw: Move proximitycheck to CMSettings.

    Change-Id: Ie80166c990363d3846925b189a1f7001a7fd56f8

Author: Pat Erley <perley@cyngn.com>
Date:   Thu Dec 10 17:00:53 2015 -0800

    PowerManagerService: Log when proximity blocks wake

    There is currently no indication when the proximity sensor
    is allowed to prevent the system from waking up.  This can
    make it hard to debug weird failed wakes.  Add a log to
    facilitate debugging wakup problems.

    Change-Id: I7df34e13b1268a4e7211fb06ccd88f2053c0af0a

Author: Christopher R. Palmer <crpalmer@gmail.com>
Date:   Fri Feb 19 11:53:15 2016 -0500

    base: Fix proximity check on power key

    To test, enable "Settings >> Display >> Prevent accidental wakeup",
    hold your hand over the proximity sensor and turn your phone on.

    Prior to this change, it will wake up the phone and after the change
    it will not.

    Change-Id: Ied300108cebb31dedf228e85510abebb3e8a4152

Author: vm03 <vasy@vasy.ru>
Date:   Sat Feb 27 17:16:02 2016 +0300

    base: Fix proximity check on non power key

    To test, enable "Settings >> Display >> Prevent accidental wake-up"
    and "Settings >> Buttons >> Home button Wake up device", hold your
    hand over the proximity sensor and turn your phone on by home key.

    Prior to this change, it will wake up the phone and after the change it will not.

    Change-Id: Ifd14ff2ad9cd2cbc64209b9cf19e3c0ee0b6f40f

Author: Roman Birg <roman@cyngn.com>
Date:   Tue Apr 26 16:39:47 2016 -0700

    only use proximity checks on wakeup keys

    The power button should always wake the screen regardless of the
    proximity; only check proximity when the wake up key code is WAKEUP.

    Ticket: CYNGNOS-2579

    Change-Id: I686ad22d513a3d939be3a0a5c3b752339b2383d3
    Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

Author: LuK1337 <priv.luk@gmail.com>
Date:   Sat May 21 11:48:13 2016 +0200

    Disable proximity check on power key properly

    Change-Id: If1ca0fa02805ce2fbe5a9ac1ab56a5e62beca4e1

Change-Id: Ia5ff446d88435773acccc7467e66009000dc20cb
parent 337acef1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ interface IPowerManager
    @UnsupportedAppUsage
    void userActivity(long time, int event, int flags);
    void wakeUp(long time, int reason, String details, String opPackageName);
    void wakeUpWithProximityCheck(long time, int reason, String details, String opPackageName);
    @UnsupportedAppUsage
    void goToSleep(long time, int reason, int flags);
    void nap(long time);
+16 −0
Original line number Diff line number Diff line
@@ -1234,6 +1234,22 @@ public final class PowerManager {
        }
    }

    /**
     * Forces the device to wake up from sleep only if
     * nothing is blocking the proximity sensor
     *
     * @see #wakeUp
     *
     * @hide
     */
    public void wakeUpWithProximityCheck(long time, @WakeReason int reason, String details) {
        try {
            mService.wakeUpWithProximityCheck(time, reason, details, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Forces the device to start napping.
     * <p>
+14 −3
Original line number Diff line number Diff line
@@ -3817,7 +3817,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
            if (isWakeKey) {
                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
                        PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
                        PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY", true);
            }
            return result;
        }
@@ -4171,8 +4171,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }

        if (isWakeKey) {
            // Check prox only on wake key
            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
                    PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
                    PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY",
                    event.getKeyCode() == KeyEvent.KEYCODE_WAKEUP);
        }

        return result;
@@ -4619,6 +4621,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
            String details) {
        return wakeUp(wakeTime, wakeInTheaterMode, reason, details, false);
    }

    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
            String details, boolean withProximityCheck) {
        final boolean theaterModeEnabled = isTheaterModeEnabled();
        if (!wakeInTheaterMode && theaterModeEnabled) {
            return false;
@@ -4629,7 +4636,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    Settings.Global.THEATER_MODE_ON, 0);
        }

        if (withProximityCheck) {
            mPowerManager.wakeUpWithProximityCheck(wakeTime, reason, details);
        } else {
            mPowerManager.wakeUp(wakeTime, reason, details);
        }
        return true;
    }

+141 −6
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -72,6 +75,7 @@ import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.telephony.TelephonyManager;
import android.util.KeyValueListParser;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -130,6 +134,8 @@ public final class PowerManagerService extends SystemService
    private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3;
    // Message: Polling to look for long held wake locks.
    private static final int MSG_CHECK_FOR_LONG_WAKELOCKS = 4;
    // Message: Sent when waking up with proximity check.
    private static final int MSG_WAKE_UP = 5;

    // Dirty bit: mWakeLocks changed
    private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -222,6 +228,8 @@ public final class PowerManagerService extends SystemService
    private static final int HALT_MODE_REBOOT = 1;
    private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;

    private static final float PROXIMITY_NEAR_THRESHOLD = 5.0f;

    // property for last reboot reason
    private static final String REBOOT_PROPERTY = "sys.boot.reason";

@@ -753,6 +761,17 @@ public final class PowerManagerService extends SystemService
    private static native int nativeGetFeature(int featureId);
    private static native boolean nativeForceSuspend();

    // Whether proximity check on wake is enabled by default
    private boolean mProximityWakeEnabledByDefaultConfig;

    private boolean mProximityWakeSupported;
    private boolean mProximityWakeEnabled;
    private int mProximityTimeOut;
    private SensorManager mSensorManager;
    private Sensor mProximitySensor;
    private SensorEventListener mProximityListener;
    private android.os.PowerManager.WakeLock mProximityWakeLock;

    public PowerManagerService(Context context) {
        this(context, new Injector());
    }
@@ -880,6 +899,10 @@ public final class PowerManagerService extends SystemService
                // Shouldn't happen since in-process.
            }

            // Initialize proximity sensor
            mSensorManager = mContext.getSystemService(SensorManager.class);
            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

            // Go.
            readConfigurationLocked();
            updateSettingsLocked();
@@ -936,7 +959,9 @@ public final class PowerManagerService extends SystemService
        resolver.registerContentObserver(LineageSettings.Secure.getUriFor(
                LineageSettings.Secure.BUTTON_BACKLIGHT_TIMEOUT),
                false, mSettingsObserver, UserHandle.USER_ALL);

        resolver.registerContentObserver(LineageSettings.System.getUriFor(
                LineageSettings.System.PROXIMITY_ON_WAKE),
                false, mSettingsObserver, UserHandle.USER_ALL);
        IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE));
        if (vrManager != null) {
            try {
@@ -1006,6 +1031,16 @@ public final class PowerManagerService extends SystemService
                com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1);
        mSupportsDoubleTapWakeConfig = resources.getBoolean(
                com.android.internal.R.bool.config_supportDoubleTapWake);
        mProximityWakeSupported = resources.getBoolean(
                org.lineageos.platform.internal.R.bool.config_proximityCheckOnWake);
        mProximityWakeEnabledByDefaultConfig = resources.getBoolean(
                org.lineageos.platform.internal.R.bool.config_proximityCheckOnWakeEnabledByDefault);
        mProximityTimeOut = resources.getInteger(
                org.lineageos.platform.internal.R.integer.config_proximityCheckTimeout);
        if (mProximityWakeSupported) {
            mProximityWakeLock = mContext.getSystemService(PowerManager.class)
                    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ProximityWakeLock");
        }
    }

    private void updateSettingsLocked() {
@@ -1061,6 +1096,9 @@ public final class PowerManagerService extends SystemService
        mButtonBrightness = LineageSettings.Secure.getIntForUser(resolver,
                LineageSettings.Secure.BUTTON_BRIGHTNESS, mButtonBrightnessSettingDefault,
                UserHandle.USER_CURRENT);
        mProximityWakeEnabled = LineageSettings.System.getInt(resolver,
                LineageSettings.System.PROXIMITY_ON_WAKE,
                mProximityWakeEnabledByDefaultConfig ? 1 : 0) == 1;

        mDirty |= DIRTY_SETTINGS;
    }
@@ -4028,6 +4066,10 @@ public final class PowerManagerService extends SystemService
                case MSG_CHECK_FOR_LONG_WAKELOCKS:
                    checkForLongWakeLocks();
                    break;
                case MSG_WAKE_UP:
                    cleanupProximity();
                    ((Runnable) msg.obj).run();
                    break;
            }
        }
    }
@@ -4449,6 +4491,20 @@ public final class PowerManagerService extends SystemService
        @Override // Binder call
        public void wakeUp(long eventTime, @WakeReason int reason, String details,
                String opPackageName) {
            wakeUp(eventTime, reason, details, opPackageName, false);
        }

        @Override // Binder call
        public void wakeUpWithProximityCheck(long eventTime, @WakeReason int reason,
                String details, String opPackageName) {
            wakeUp(eventTime, reason, details, opPackageName, true);
        }

        /**
         * @hide
         */
        public void wakeUp(long eventTime, @WakeReason int reason, String details,
                String opPackageName, boolean checkProximity) {
            if (eventTime > SystemClock.uptimeMillis()) {
                throw new IllegalArgumentException("event time must not be in the future");
            }
@@ -4457,12 +4513,19 @@ public final class PowerManagerService extends SystemService
                    android.Manifest.permission.DEVICE_POWER, null);

            final int uid = Binder.getCallingUid();
            final Runnable r = () -> {
                final long ident = Binder.clearCallingIdentity();
                try {
                    wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            };
            if (checkProximity) {
                runWithProximityCheck(r);
            } else {
                r.run();
            }
        }

        @Override // Binder call
@@ -5100,4 +5163,76 @@ public final class PowerManagerService extends SystemService
            nativeSetFeature(featureId, data);
        }
    }

    private void cleanupProximity() {
        synchronized (mProximityWakeLock) {
            cleanupProximityLocked();
        }
    }

    private void cleanupProximityLocked() {
        if (mProximityWakeLock.isHeld()) {
            mProximityWakeLock.release();
        }
        if (mProximityListener != null) {
            mSensorManager.unregisterListener(mProximityListener);
            mProximityListener = null;
        }
    }

    private void runWithProximityCheck(final Runnable r) {
        if (mHandler.hasMessages(MSG_WAKE_UP)) {
            // A message is already queued
            return;
        }

        final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
        final boolean hasIncomingCall = tm.getCallState() == TelephonyManager.CALL_STATE_RINGING;

        if (mProximityWakeSupported && mProximityWakeEnabled
                && mProximitySensor != null && !hasIncomingCall) {
            final Message msg = mHandler.obtainMessage(MSG_WAKE_UP);
            msg.obj = r;
            mHandler.sendMessageDelayed(msg, mProximityTimeOut);
            runPostProximityCheck(r);
        } else {
            r.run();
        }
    }

    private void runPostProximityCheck(final Runnable r) {
        if (mSensorManager == null) {
            r.run();
            return;
        }
        synchronized (mProximityWakeLock) {
            mProximityWakeLock.acquire();
            mProximityListener = new SensorEventListener() {
                @Override
                public void onSensorChanged(SensorEvent event) {
                    cleanupProximityLocked();
                    if (!mHandler.hasMessages(MSG_WAKE_UP)) {
                        Slog.w(TAG, "Proximity sensor took too long, "
                                + "wake event already triggered!");
                        return;
                    }
                    mHandler.removeMessages(MSG_WAKE_UP);
                    final float distance = event.values[0];
                    if (distance >= PROXIMITY_NEAR_THRESHOLD ||
                            distance >= mProximitySensor.getMaximumRange()) {
                        r.run();
                    } else {
                        Slog.w(TAG, "Not waking up. Proximity sensor is blocked.");
                    }
                }

                @Override
                public void onAccuracyChanged(Sensor sensor, int accuracy) {
                    // Do nothing
                }
            };
            mSensorManager.registerListener(mProximityListener,
                   mProximitySensor, SensorManager.SENSOR_DELAY_FASTEST);
        }
    }
}