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