From 1d7a50cea800d667ab886b3ea3e8aef9923ba59c Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Tue, 28 Apr 2020 13:51:40 -0400 Subject: [PATCH] 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 --- packages/SystemUI/res/values/config.xml | 14 ++++- .../systemui/util/sensors/SensorModule.java | 2 + .../util/sensors/ThresholdSensorImpl.java | 61 ++++++++++++++++--- .../util/sensors/ThresholdSensorImplTest.java | 60 ++++++++++++++++-- 4 files changed, 124 insertions(+), 13 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e60b543059569..e32fe4da2bf60 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -205,14 +205,26 @@ far break points. A sensor value less than this is considered "near". --> + + + - + + + 130 diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java index 5a93e6c9f77a9..c5a658f298dca 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java @@ -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(); diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java index 333e8da2a84f3..5bedea173f197 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorImpl.java @@ -44,14 +44,16 @@ class ThresholdSensorImpl implements ThresholdSensor { private List 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) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java index 70b92dc014472..0d36bd30c8a54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java @@ -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();