Leave Prox registered when safe to do so.

This CL allows a proximity sensor operating in dual mode to
leave its secondary sensor regitered where it is told it is
safe to do so. This is generally when the screen is in some
sort of doze or aod mode. The sensor does not itself manage
this state but expects clients to tell it when it it safe.

Fixes: 157717162
Test: atest SystemUITests && manual
Change-Id: Ie89e80aa7440b4964fb61c144ae3b8bc4808f0ac
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 59aba3e..aebf41b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -37,6 +37,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.Display;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -266,6 +267,13 @@
         }
     }
 
+    void onScreenState(int state) {
+        mProximitySensor.setSecondarySafe(
+                state == Display.STATE_DOZE
+                || state == Display.STATE_DOZE_SUSPEND
+                || state == Display.STATE_OFF);
+    }
+
     public void setProxListening(boolean listen) {
         if (mProximitySensor.isRegistered() && listen) {
             mProximitySensor.alertListeners();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index d02cafb..c4e6975 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -423,6 +423,7 @@
 
     @Override
     public void onScreenState(int state) {
+        mDozeSensors.onScreenState(state);
         if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND
                 || state == Display.STATE_OFF) {
             mDozeSensors.setProxListening(mWantProx);
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 ff7716a..c5a66a7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -72,6 +72,7 @@
     private final AtomicBoolean mAlerting = new AtomicBoolean();
     private Runnable mCancelSecondaryRunnable;
     private boolean mInitializedListeners = false;
+    private boolean mSecondarySafe = false;
 
     private ThresholdSensor.Listener mPrimaryEventListener = new ThresholdSensor.Listener() {
         @Override
@@ -83,21 +84,22 @@
     private ThresholdSensor.Listener mSecondaryEventListener = new ThresholdSensor.Listener() {
         @Override
         public void onThresholdCrossed(ThresholdSensorEvent event) {
-            // Only check the secondary as long as the primary thinks we're near.
-            if (!mLastPrimaryEvent.getBelow()) {
+            // If we no longer have a "below" signal and the secondary sensor is not
+            // considered "safe", then we need to turn it off.
+            if (!mSecondarySafe && (!mLastPrimaryEvent.getBelow() || !event.getBelow())) {
                 mSecondaryThresholdSensor.pause();
-                mCancelSecondaryRunnable = null;
-                return;
+                if (!mLastPrimaryEvent.getBelow()) {
+                    // Only check the secondary as long as the primary thinks we're near.
+                    mCancelSecondaryRunnable = null;
+                    return;
+                } else {
+                    // Check this sensor again in a moment.
+                    mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(
+                            mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS);
+                }
             }
             logDebug("Secondary sensor event: " + event.getBelow() + ".");
 
-            // This sensor should only be used briefly when uncovered.
-            if (!event.getBelow()) {
-                mSecondaryThresholdSensor.pause();
-                // Check this sensor again in a moment.
-                mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(
-                        mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS);
-            }
             onSensorEvent(event);
         }
     };
@@ -145,6 +147,15 @@
         registerInternal();
     }
 
+    /**
+     * Sets that it is safe to leave the secondary sensor on indefinitely.
+     */
+    public void setSecondarySafe(boolean safe) {
+        mSecondarySafe = safe;
+        if (!mSecondarySafe) {
+            mSecondaryThresholdSensor.pause();
+        }
+    }
 
     /**
      * Returns true if we are registered with the SensorManager.
@@ -278,6 +289,10 @@
             return;
         }
 
+        if (!mSecondarySafe && !event.getBelow()) {
+            mSecondaryThresholdSensor.pause();
+        }
+
         mLastEvent = event;
         alertListeners();
     }
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 433ec18..bb498d7 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
@@ -292,6 +292,38 @@
         mProximitySensor.unregister(listener);
     }
 
+    @Test
+    public void testSecondarySafe() {
+        mProximitySensor.setSecondarySafe(true);
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        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 secondary sensor should now remain resumed indefinitely.
+        assertFalse(mThresholdSensorSecondary.isPaused());
+        mThresholdSensorPrimary.triggerEvent(false, 1);
+        assertFalse(listener.mLastEvent.getBelow());
+        assertEquals(2, listener.mCallCount);
+
+        // The secondary is still running, and not polling with the executor.
+        assertFalse(mThresholdSensorSecondary.isPaused());
+        assertEquals(0, mFakeExecutor.numPending());
+
+        mProximitySensor.unregister(listener);
+    }
+
     private static class TestableListener implements ThresholdSensor.Listener {
         ThresholdSensor.ThresholdSensorEvent mLastEvent;
         int mCallCount = 0;