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

Commit 1d7a50ce authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Add latching threshold for ThresholdSensorImpl

This allows ThresholdSensorImpl to account for noise in their sensor
output. They must go below one threshold to trigger a "below" output,
and then must go above a different threshold to switch back to an
"above" state.

This new second, latching threshold is optional and defaults to the
existing threshold if not set.

For the ProximitySensor, we introduce proximity_sensor_threshold_latch
and proximity_sensor_secondary_threshold_latch in config.xml.

Fixes: 147026387
Test: atest SystemUITests && manual
Change-Id: Ie0b7b357a48fd27424d12b890cda9e00073e1eb3
parent 11ba5861
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -205,14 +205,26 @@
         far break points. A sensor value less than this is considered "near". -->
    <item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item>

    <!-- If using proximity_sensor_type, specifies a threshold value to distinguish near and
         far break points. A sensor value more than this is considered "far". If not set,
         proximity_sensor_threshold is used. This allows one to implement a latching mechanism for
         noisy sensors. -->
    <item name="proximity_sensor_threshold_latch" translatable="false" format="float" type="dimen"></item>

    <!-- Override value to use for proximity sensor as confirmation for proximity_sensor_type. -->
    <string name="proximity_sensor_secondary_type" translatable="false"></string>

    <!-- If using proximity_sensor_confirmation_type, specifies a threshold value to distinguish
    <!-- If using proximity_sensor_secondary_type, specifies a threshold value to distinguish
         near and far break points. A sensor value less than this is considered "near". -->
    <item name="proximity_sensor_secondary_threshold" translatable="false" format="float"
          type="dimen"></item>

    <!-- If using proximity_sensor_secondary_type, specifies a threshold value to distinguish near and
         far break points. A sensor value more than this is considered "far". If not set,
         proximity_sensor_secondary_threshold is used. This allows one to implement a latching
         mechanism for noisy sensors. -->
    <item name="proximity_sensor_secondary_threshold_latch" translatable="false" format="float" type="dimen"></item>

    <!-- Doze: pulse parameter - how long does it take to fade in? -->
    <integer name="doze_pulse_duration_in">130</integer>

+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ public class SensorModule {
                    .setSensorDelay(SensorManager.SENSOR_DELAY_NORMAL)
                    .setSensorResourceId(R.string.proximity_sensor_type)
                    .setThresholdResourceId(R.dimen.proximity_sensor_threshold)
                    .setThresholdLatchResourceId(R.dimen.proximity_sensor_threshold_latch)
                    .build();
        } catch (IllegalStateException e) {
            Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
@@ -56,6 +57,7 @@ public class SensorModule {
            return thresholdSensorBuilder
                    .setSensorResourceId(R.string.proximity_sensor_secondary_type)
                    .setThresholdResourceId(R.dimen.proximity_sensor_secondary_threshold)
                    .setThresholdLatchResourceId(R.dimen.proximity_sensor_secondary_threshold_latch)
                    .build();
        } catch (IllegalStateException e) {
            return thresholdSensorBuilder.setSensor(null).setThresholdValue(0).build();
+54 −7
Original line number Diff line number Diff line
@@ -44,14 +44,16 @@ class ThresholdSensorImpl implements ThresholdSensor {
    private List<Listener> mListeners = new ArrayList<>();
    private Boolean mLastBelow;
    private String mTag;
    private final float mThresholdLatch;
    private int mSensorDelay;

    private SensorEventListener mSensorEventListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            boolean below = event.values[0] < mThreshold;
            boolean above = event.values[0] > mThresholdLatch;
            logDebug("Sensor value: " + event.values[0]);
            onSensorEvent(below, event.timestamp);
            onSensorEvent(below, above, event.timestamp);
        }

        @Override
@@ -60,10 +62,11 @@ class ThresholdSensorImpl implements ThresholdSensor {
    };

    private ThresholdSensorImpl(AsyncSensorManager sensorManager,
            Sensor sensor, float threshold, int sensorDelay) {
            Sensor sensor, float threshold, float thresholdLatch, int sensorDelay) {
        mSensorManager = sensorManager;
        mSensor = sensor;
        mThreshold = threshold;
        mThresholdLatch = thresholdLatch;
        mSensorDelay = sensorDelay;
    }

@@ -165,13 +168,32 @@ class ThresholdSensorImpl implements ThresholdSensor {
        mLastBelow = null;  // Forget what we know.
    }

    private void onSensorEvent(boolean below, long timestampNs) {
    /**
     * Call when the sensor reports a new value.
     *
     * Separate below-threshold and above-thresholds are specified. this allows latching behavior,
     * where a different threshold can be specified for triggering the sensor depending on if it's
     * going from above to below or below to above. To outside listeners of this class, the class
     * still appears entirely binary.
     */
    private void onSensorEvent(boolean belowThreshold, boolean aboveThreshold, long timestampNs) {
        Assert.isMainThread();
        if (!mRegistered || mLastBelow != null && mLastBelow == below) {
        if (!mRegistered) {
            return;
        }
        mLastBelow = below;
        alertListenersInternal(below, timestampNs);
        if (mLastBelow != null) {
            // If we last reported below and are not yet above, change nothing.
            if (mLastBelow && !aboveThreshold) {
                return;
            }
            // If we last reported above and are not yet below, change nothing.
            if (!mLastBelow && !belowThreshold) {
                return;
            }
        }
        mLastBelow = belowThreshold;
        logDebug("Alerting below: " + belowThreshold);
        alertListenersInternal(belowThreshold, timestampNs);
    }


@@ -192,9 +214,11 @@ class ThresholdSensorImpl implements ThresholdSensor {
        private final AsyncSensorManager mSensorManager;
        private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;;
        private float mThresholdValue;
        private float mThresholdLatchValue;
        private Sensor mSensor;
        private boolean mSensorSet;
        private boolean mThresholdSet;
        private boolean mThresholdLatchValueSet;

        @Inject
        Builder(@Main Resources resources, AsyncSensorManager sensorManager) {
@@ -222,6 +246,15 @@ class ThresholdSensorImpl implements ThresholdSensor {
            return this;
        }

        Builder setThresholdLatchResourceId(int thresholdLatchResourceId) {
            try {
                setThresholdLatchValue(mResources.getFloat(thresholdLatchResourceId));
            } catch (Resources.NotFoundException e) {
                // no-op
            }
            return this;
        }

        Builder setSensorType(String sensorType) {
            Sensor sensor = findSensorByType(sensorType);
            if (sensor != null) {
@@ -233,6 +266,15 @@ class ThresholdSensorImpl implements ThresholdSensor {
        Builder setThresholdValue(float thresholdValue) {
            mThresholdValue = thresholdValue;
            mThresholdSet = true;
            if (!mThresholdLatchValueSet) {
                mThresholdLatchValue = mThresholdValue;
            }
            return this;
        }

        Builder setThresholdLatchValue(float thresholdLatchValue) {
            mThresholdLatchValue = thresholdLatchValue;
            mThresholdLatchValueSet = true;
            return this;
        }

@@ -254,8 +296,13 @@ class ThresholdSensorImpl implements ThresholdSensor {
                throw new IllegalStateException("A threshold was not successfully set.");
            }

            if (mThresholdValue > mThresholdLatchValue) {
                throw new IllegalStateException(
                        "Threshold must be less than or equal to Threshold Latch");
            }

            return new ThresholdSensorImpl(
                    mSensorManager, mSensor, mThresholdValue, mSensorDelay);
                    mSensorManager, mSensor, mThresholdValue, mThresholdLatchValue, mSensorDelay);
        }

        private Sensor findSensorByType(String sensorType) {
+55 −5
Original line number Diff line number Diff line
@@ -37,19 +37,21 @@ import org.junit.runner.RunWith;
public class ThresholdSensorImplTest extends SysuiTestCase {

    private ThresholdSensorImpl mThresholdSensor;
    private FakeSensorManager mSensorManager;
    private AsyncSensorManager mAsyncSensorManager;
    private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;

    @Before
    public void setUp() throws Exception {
        allowTestableLooperAsMainThread();
        FakeSensorManager sensorManager = new FakeSensorManager(getContext());
        mSensorManager = new FakeSensorManager(getContext());

        AsyncSensorManager asyncSensorManager = new AsyncSensorManager(
                sensorManager, null, new Handler());
        mAsyncSensorManager = new AsyncSensorManager(
                mSensorManager, null, new Handler());

        mFakeProximitySensor = sensorManager.getFakeProximitySensor();
        mFakeProximitySensor = mSensorManager.getFakeProximitySensor();
        ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
                null, asyncSensorManager);
                null, mAsyncSensorManager);
        mThresholdSensor = (ThresholdSensorImpl) thresholdSensorBuilder
                .setSensor(mFakeProximitySensor.getSensor())
                .setThresholdValue(mFakeProximitySensor.getSensor().getMaximumRange())
@@ -226,6 +228,54 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
        waitForSensorManager();
    }

    @Test
    public void testHysteresis() {
        float lowValue = 10f;
        float highValue = 100f;
        FakeSensorManager.FakeGenericSensor sensor = mSensorManager.getFakeLightSensor();
        ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
                null, mAsyncSensorManager);
        ThresholdSensorImpl thresholdSensor = (ThresholdSensorImpl) thresholdSensorBuilder
                .setSensor(sensor.getSensor())
                .setThresholdValue(lowValue)
                .setThresholdLatchValue(highValue)
                .build();

        TestableListener listener = new TestableListener();

        assertFalse(thresholdSensor.isRegistered());
        thresholdSensor.register(listener);
        waitForSensorManager();
        assertTrue(thresholdSensor.isRegistered());
        assertEquals(0, listener.mCallCount);

        sensor.sendSensorEvent(lowValue - 1);

        assertTrue(listener.mBelow);
        assertEquals(1, listener.mCallCount);

        sensor.sendSensorEvent(lowValue + 1);

        assertTrue(listener.mBelow);
        assertEquals(1, listener.mCallCount);

        sensor.sendSensorEvent(highValue + 1);

        assertFalse(listener.mBelow);
        assertEquals(2, listener.mCallCount);

        sensor.sendSensorEvent(highValue - 1);

        assertFalse(listener.mBelow);
        assertEquals(2, listener.mCallCount);


        sensor.sendSensorEvent(lowValue - 1);

        assertTrue(listener.mBelow);
        assertEquals(3, listener.mCallCount);
    }

    @Test
    public void testAlertAfterPause() {
        TestableListener listener = new TestableListener();