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

Commit 46b9d68f authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Add new ProximitySensor wrapper that automatically uses appropriate sensor.

Bug: 140270231
Test: manual && atest SystemUITests
Change-Id: Id151ce8f702f7deadab73ee3904a0a883870b237
Merged-In: Id151ce8f702f7deadab73ee3904a0a883870b237
parent d65f8c67
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.AsyncSensorManager;
import com.android.systemui.util.ProximitySensor;

import java.io.PrintWriter;

@@ -50,18 +50,23 @@ import javax.inject.Singleton;
@Singleton
public class FalsingManagerProxy implements FalsingManager {

    private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";

    private final ProximitySensor mProximitySensor;
    private FalsingManager mInternalFalsingManager;
    private final Handler mMainHandler;

    @Inject
    FalsingManagerProxy(Context context, PluginManager pluginManager,
            @Named(MAIN_HANDLER_NAME) Handler handler) {
            @Named(MAIN_HANDLER_NAME) Handler handler,
            ProximitySensor proximitySensor) {
        mMainHandler = handler;
        mProximitySensor = proximitySensor;
        mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                command -> mMainHandler.post(command),
                properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace())
        );
        setupFalsingManager(context);
        );        setupFalsingManager(context);
        final PluginListener<FalsingPlugin> mPluginListener = new PluginListener<FalsingPlugin>() {
            public void onPluginConnected(FalsingPlugin plugin, Context context) {
                FalsingManager pluginFalsingManager = plugin.getFalsingManager(context);
@@ -103,8 +108,8 @@ public class FalsingManagerProxy implements FalsingManager {
        } else {
            mInternalFalsingManager = new BrightLineFalsingManager(
                    new FalsingDataProvider(context.getResources().getDisplayMetrics()),
                    Dependency.get(AsyncSensorManager.class),
                    KeyguardUpdateMonitor.getInstance(context)
                    Dependency.get(KeyguardUpdateMonitor.class),
                    mProximitySensor
            );
        }

+10 −38
Original line number Diff line number Diff line
@@ -19,10 +19,6 @@ package com.android.systemui.classifier.brightline;
import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED;
import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricSourceType;
import android.net.Uri;
import android.util.Log;
@@ -33,12 +29,11 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.util.ProximitySensor;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * FalsingManager designed to make clear why a touch was rejected.
@@ -48,9 +43,9 @@ public class BrightLineFalsingManager implements FalsingManager {
    static final boolean DEBUG = false;
    private static final String TAG = "FalsingManagerPlugin";

    private final SensorManager mSensorManager;
    private final FalsingDataProvider mDataProvider;
    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    private final ProximitySensor mProximitySensor;
    private boolean mSessionStarted;
    private MetricsLogger mMetricsLogger;
    private int mIsFalseTouchCalls;
@@ -58,20 +53,9 @@ public class BrightLineFalsingManager implements FalsingManager {
    private boolean mScreenOn;
    private boolean mJustUnlockedWithFace;

    private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor();

    private final List<FalsingClassifier> mClassifiers;

    private SensorEventListener mSensorEventListener = new SensorEventListener() {
        @Override
        public synchronized void onSensorChanged(SensorEvent event) {
            onSensorEvent(event);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    private ProximitySensor.ProximitySensorListener mSensorEventListener = this::onProximityEvent;

    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
            new KeyguardUpdateMonitorCallback() {
@@ -87,11 +71,11 @@ public class BrightLineFalsingManager implements FalsingManager {

    public BrightLineFalsingManager(
            FalsingDataProvider falsingDataProvider,
            SensorManager sensorManager,
            KeyguardUpdateMonitor keyguardUpdateMonitor) {
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            ProximitySensor proximitySensor) {
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mDataProvider = falsingDataProvider;
        mSensorManager = sensorManager;
        mProximitySensor = proximitySensor;
        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);

        mMetricsLogger = new MetricsLogger();
@@ -108,24 +92,12 @@ public class BrightLineFalsingManager implements FalsingManager {
    }

    private void registerSensors() {
        Sensor s = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        if (s != null) {
            // This can be expensive, and doesn't need to happen on the main thread.
            mBackgroundExecutor.submit(() -> {
                logDebug("registering sensor listener");
                mSensorManager.registerListener(
                        mSensorEventListener, s, SensorManager.SENSOR_DELAY_GAME);
            });
        }
        mProximitySensor.register(mSensorEventListener);
    }


    private void unregisterSensors() {
        // This can be expensive, and doesn't need to happen on the main thread.
        mBackgroundExecutor.submit(() -> {
            logDebug("unregistering sensor listener");
            mSensorManager.unregisterListener(mSensorEventListener);
        });
        mProximitySensor.unregister(mSensorEventListener);
    }

    private void sessionStart() {
@@ -187,10 +159,10 @@ public class BrightLineFalsingManager implements FalsingManager {
        mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
    }

    private void onSensorEvent(SensorEvent sensorEvent) {
    private void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {
        // TODO: some of these classifiers might allow us to abort early, meaning we don't have to
        // make these calls.
        mClassifiers.forEach((classifier) -> classifier.onSensorEvent(sensorEvent));
        mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
    }

    @Override
+3 −3
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package com.android.systemui.classifier.brightline;

import android.hardware.SensorEvent;
import android.view.MotionEvent;

import com.android.systemui.classifier.Classifier;
import com.android.systemui.util.ProximitySensor;

import java.util.List;

@@ -98,9 +98,9 @@ abstract class FalsingClassifier {
    void onTouchEvent(MotionEvent motionEvent) {};

    /**
     * Called whenever a SensorEvent occurs, specifically the ProximitySensor.
     * Called when a ProximityEvent occurs (change in near/far).
     */
    void onSensorEvent(SensorEvent sensorEvent) {};
    void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {};

    /**
     * The phone screen has turned on and we need to begin falsing detection.
+8 −10
Original line number Diff line number Diff line
@@ -19,11 +19,11 @@ package com.android.systemui.classifier.brightline;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.provider.DeviceConfig;
import android.view.MotionEvent;

import com.android.systemui.util.ProximitySensor;


/**
 * False touch if proximity sensor is covered for more than a certain percentage of the gesture.
@@ -97,14 +97,12 @@ class ProximityClassifier extends FalsingClassifier {
    }

    @Override
    public void onSensorEvent(SensorEvent sensorEvent) {
        if (sensorEvent.sensor.getType() == Sensor.TYPE_PROXIMITY) {
            logDebug("Sensor is: " + (sensorEvent.values[0] < sensorEvent.sensor.getMaximumRange())
                    + " at time " + sensorEvent.timestamp);
            update(
                    sensorEvent.values[0] < sensorEvent.sensor.getMaximumRange(),
                    sensorEvent.timestamp);
        }
    public void onProximityEvent(
            ProximitySensor.ProximityEvent proximityEvent) {
        boolean near = proximityEvent.getNear();
        long timestampNs = proximityEvent.getTimestampNs();
        logDebug("Sensor is: " + near + " at time " + timestampNs);
        update(near, timestampNs);
    }

    @Override
+186 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.util;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;

import com.android.systemui.R;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

/**
 * Simple wrapper around SensorManager customized for the Proximity sensor.
 */
public class ProximitySensor {
    private static final String TAG = "ProxSensor";
    private static final boolean DEBUG = false;

    private final Sensor mSensor;
    private final AsyncSensorManager mSensorManager;
    private final boolean mUsingBrightnessSensor;
    private final float mMaxRange;

    private SensorEventListener mSensorEventListener = new SensorEventListener() {
        @Override
        public synchronized void onSensorChanged(SensorEvent event) {
            onSensorEvent(event);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    private boolean mNear;
    private List<ProximitySensorListener> mListeners = new ArrayList<>();
    private String mTag = null;

    @Inject
    public ProximitySensor(Context context, AsyncSensorManager sensorManager) {
        mSensorManager = sensorManager;
        Sensor sensor = findBrightnessSensor(context, sensorManager);

        if (sensor == null) {
            mUsingBrightnessSensor = false;
            sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        } else {
            mUsingBrightnessSensor = true;
        }
        mSensor = sensor;
        if (mSensor != null) {
            mMaxRange = mSensor.getMaximumRange();
        } else {
            mMaxRange = 0;
        }
    }

    public void setTag(String tag) {
        mTag = tag;
    }

    private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) {
        String sensorType = context.getString(R.string.doze_brightness_sensor_type);
        List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
        Sensor sensor = null;
        for (Sensor s : sensorList) {
            if (sensorType.equals(s.getStringType())) {
                sensor = s;
                break;
            }
        }

        return sensor;
    }

    /**
     * Returns {@code false} if a Proximity sensor is not available.
     */
    public boolean getSensorAvailable() {
        return mSensor != null;
    }

    /**
     * Add a listener.
     *
     * Registers itself with the {@link SensorManager} if this is the first listener
     * added.
     */
    public boolean register(ProximitySensorListener listener) {
        if (!getSensorAvailable()) {
            return false;
        }

        logDebug("using brightness sensor? " + mUsingBrightnessSensor);
        mListeners.add(listener);
        if (mListeners.size() == 1) {
            logDebug("registering sensor listener");
            mSensorManager.registerListener(
                    mSensorEventListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
        }

        return true;
    }

    /**
     * Remove a listener.
     *
     * If all listeners are removed from an instance of this class,
     * it will unregister itself with the SensorManager.
     */
    public void unregister(ProximitySensorListener listener) {
        mListeners.remove(listener);
        if (mListeners.size() == 0) {
            logDebug("unregistering sensor listener");
            mSensorManager.unregisterListener(mSensorEventListener);
        }
    }

    public boolean isNear() {
        return getSensorAvailable() && mNear;
    }

    private void onSensorEvent(SensorEvent event) {
        boolean near = event.values[0] < mMaxRange;
        if (mUsingBrightnessSensor) {
            near = event.values[0] == 0;
        }
        mNear = near;
        mListeners.forEach(proximitySensorListener ->
                proximitySensorListener.onProximitySensorEvent(
                        new ProximityEvent(mNear, event.timestamp)));
    }

    /** Implement to be notified of ProximityEvents. */
    public interface ProximitySensorListener {
        /** Called when the ProximitySensor changes. */
        void onProximitySensorEvent(ProximityEvent proximityEvent);
    }

    /**
     * Returned when the near/far state of a {@link ProximitySensor} changes.
     */
    public static class ProximityEvent {
        private final boolean mNear;
        private final long mTimestampNs;

        public ProximityEvent(boolean near, long timestampNs) {
            mNear = near;
            mTimestampNs = timestampNs;
        }

        public boolean getNear() {
            return mNear;
        }

        public long getTimestampNs() {
            return mTimestampNs;
        }
    }

    private void logDebug(String msg) {
        if (DEBUG) {
            Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
        }
    }
}
Loading