From f354c67bd8c32439c6392228722ff00d8b5d74b8 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 1 May 2020 10:21:26 -0400 Subject: [PATCH] Prevent NPE in ProximitySensor. There was a pseudo-race in ProximitySensor where, if a listener tried to cancel its proximity sensor, the sensor would then add a delayed runnable _after_ being canceled, causing it to NPE the next time it ran. This only occured on phones using a dual-sensor approach to proximity. It happened particularly regularly with the ProxCheck utility class. Fixes: 155183913 Test: atest SystemUITests && manual. Change-Id: Id399c6d577e3c43f91a3d3a2e3b49fd4fa1918e4 --- .../util/sensors/ProximitySensor.java | 4 +-- .../util/sensors/ProximitySensorDualTest.java | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java index 9be42f3fc5f48..a59d101c9f11b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java @@ -92,11 +92,11 @@ public class ProximitySensor implements ThresholdSensor { } logDebug("Secondary sensor event: " + event.getBelow() + "."); - onSensorEvent(event); - // Check this sensor again in a moment. mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed( mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS); + + onSensorEvent(event); } }; diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java index a39c201695183..81a57478f6efb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java @@ -262,6 +262,37 @@ public class ProximitySensorDualTest extends SysuiTestCase { mProximitySensor.unregister(listener); } + @Test + public void testSecondaryCancelsSecondary() { + TestableListener listener = new TestableListener(); + ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() { + @Override + public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) { + mProximitySensor.pause(); + } + }; + + mProximitySensor.register(listener); + mProximitySensor.register(cancelingListener); + assertNull(listener.mLastEvent); + assertEquals(0, listener.mCallCount); + + mThresholdSensorPrimary.triggerEvent(true, 0); + assertNull(listener.mLastEvent); + assertEquals(0, listener.mCallCount); + mThresholdSensorSecondary.triggerEvent(true, 0); + assertTrue(listener.mLastEvent.getBelow()); + assertEquals(1, listener.mCallCount); + + // The proximity sensor should now be canceled. Advancing the clock should do nothing. + assertEquals(0, mFakeExecutor.numPending()); + mThresholdSensorSecondary.triggerEvent(false, 1); + assertTrue(listener.mLastEvent.getBelow()); + assertEquals(1, listener.mCallCount); + + mProximitySensor.unregister(listener); + } + private static class TestableListener implements ThresholdSensor.Listener { ThresholdSensor.ThresholdSensorEvent mLastEvent; int mCallCount = 0;