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();