diff options
6 files changed, 184 insertions, 17 deletions
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index e19a32e72a98..87e048cdd4a9 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -86,6 +86,10 @@ public class AmbientDisplayConfiguration { && wakeScreenGestureAvailable(); } + public long getWakeLockScreenDebounce() { + return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce); + } + public String doubleTapSensorType() { return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType); } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 489ceb72ad60..0041bfc3060d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2272,6 +2272,7 @@ <!-- If the sensor that wakes up the lock screen is available or not. --> <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool> + <integer name="config_dozeWakeLockScreenDebounce">3000</integer> <!-- Control whether the always on display mode is available. This should only be enabled on devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1f73dda18c7b..be7aaa42a420 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3404,6 +3404,7 @@ <java-symbol type="string" name="config_dozeLongPressSensorType" /> <java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" /> + <java-symbol type="integer" name="config_dozeWakeLockScreenDebounce" /> <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" /> <java-symbol type="array" name="config_allowedSystemInstantAppSettings" /> diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 2d1dba6f79c8..d1e127d91db8 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -38,6 +38,8 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.VisibleForTesting; + import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; @@ -60,7 +62,6 @@ public class DozeSensors { private final Context mContext; private final AlarmManager mAlarmManager; private final SensorManager mSensorManager; - private final TriggerSensor[] mSensors; private final ContentResolver mResolver; private final TriggerSensor mPickupSensor; private final DozeParameters mDozeParameters; @@ -68,10 +69,12 @@ public class DozeSensors { private final WakeLock mWakeLock; private final Consumer<Boolean> mProxCallback; private final Callback mCallback; + @VisibleForTesting + protected final TriggerSensor[] mSensors; private final Handler mHandler = new Handler(); private final ProxSensor mProxSensor; - + private long mDebounceFrom; public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, @@ -134,13 +137,21 @@ public class DozeSensors { mConfig.wakeScreenGestureAvailable() && alwaysOn, DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, - false /* touchscreen */), + false /* touchscreen */, mConfig.getWakeLockScreenDebounce()), }; mProxSensor = new ProxSensor(policy); mCallback = callback; } + /** + * Temporarily disable some sensors to avoid turning on the device while the user is + * turning it off. + */ + public void requestTemporaryDisable() { + mDebounceFrom = SystemClock.uptimeMillis(); + } + private Sensor findSensorWithType(String type) { return findSensorWithType(mSensorManager, type); } @@ -320,7 +331,8 @@ public class DozeSensors { } } - private class TriggerSensor extends TriggerEventListener { + @VisibleForTesting + class TriggerSensor extends TriggerEventListener { final Sensor mSensor; final boolean mConfigured; final int mPulseReason; @@ -467,23 +479,25 @@ public class DozeSensors { /** * A Sensor that is injected via plugin. */ - private class PluginSensor extends TriggerSensor { + @VisibleForTesting + class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener { - private final SensorManagerPlugin.Sensor mPluginSensor; - private final SensorManagerPlugin.SensorEventListener mTriggerEventListener = (event) -> { - DozeLog.traceSensor(mContext, mPulseReason); - mHandler.post(mWakeLock.wrap(() -> { - if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event)); - mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1, - event.getValues()); - })); - }; + final SensorManagerPlugin.Sensor mPluginSensor; + private long mDebounce; PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) { + this(sensor, setting, configured, pulseReason, reportsTouchCoordinates, + requiresTouchscreen, 0L /* debounce */); + } + + PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, + int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, + long debounce) { super(null, setting, configured, pulseReason, reportsTouchCoordinates, requiresTouchscreen); mPluginSensor = sensor; + mDebounce = debounce; } @Override @@ -492,11 +506,11 @@ public class DozeSensors { AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager; if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting) && !mRegistered) { - asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener); + asyncSensorManager.registerPluginListener(mPluginSensor, this); mRegistered = true; if (DEBUG) Log.d(TAG, "registerPluginListener"); } else if (mRegistered) { - asyncSensorManager.unregisterPluginListener(mPluginSensor, mTriggerEventListener); + asyncSensorManager.unregisterPluginListener(mPluginSensor, this); mRegistered = false; if (DEBUG) Log.d(TAG, "unregisterPluginListener"); } @@ -524,6 +538,21 @@ public class DozeSensors { } return sb.append(']').toString(); } + + @Override + public void onSensorChanged(SensorManagerPlugin.SensorEvent event) { + DozeLog.traceSensor(mContext, mPulseReason); + mHandler.post(mWakeLock.wrap(() -> { + final long now = SystemClock.uptimeMillis(); + if (now < mDebounceFrom + mDebounce) { + if (DEBUG) Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event)); + return; + } + if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event)); + mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1, + event.getValues()); + })); + } } public interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 70bf903cd712..b6e830cb50ea 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -143,8 +143,12 @@ public class DozeTriggers implements DozeMachine.Part { if (isWakeDisplay) { onWakeScreen(wakeEvent, mMachine.getState()); - } else if (isLongPress || isWakeLockScreen) { + } else if (isLongPress) { requestPulse(pulseReason, sensorPerformedProxCheck); + } else if (isWakeLockScreen) { + if (wakeEvent) { + requestPulse(pulseReason, sensorPerformedProxCheck); + } } else { proximityCheckThenCall((result) -> { if (result == ProximityCheck.RESULT_NEAR) { @@ -228,6 +232,7 @@ public class DozeTriggers implements DozeMachine.Part { if (mDockManager != null) { mDockManager.addListener(mDockEventListener); } + mDozeSensors.requestTemporaryDisable(); checkTriggersAtInit(); break; case DOZE: @@ -250,6 +255,9 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors.setTouchscreenSensorsListening(false); mDozeSensors.setProxListening(true); break; + case DOZE_PULSE_DONE: + mDozeSensors.requestTemporaryDisable(); + break; case FINISH: mBroadcastReceiver.unregister(mContext); mDozeHost.removeCallback(mHostCallback); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java new file mode 100644 index 000000000000..066dff28fb25 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.doze; + +import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.AlarmManager; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.SensorManagerPlugin; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.wakelock.WakeLock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.function.Consumer; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class DozeSensorsTest extends SysuiTestCase { + + @Mock + private AlarmManager mAlarmManager; + @Mock + private AsyncSensorManager mSensorManager; + @Mock + private DozeParameters mDozeParameters; + @Mock + private AmbientDisplayConfiguration mAmbientDisplayConfiguration; + @Mock + private WakeLock mWakeLock; + @Mock + private DozeSensors.Callback mCallback; + @Mock + private Consumer<Boolean> mProxCallback; + @Mock + private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy; + private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; + private TestableLooper mTestableLooper; + private DozeSensors mDozeSensors; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mTestableLooper = TestableLooper.get(this); + when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L); + when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(mWakeLock).wrap(any(Runnable.class)); + mDozeSensors = new TestableDozeSensors(); + } + + @Test + public void testSensorDebounce() { + mDozeSensors.setListening(true); + + mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); + mTestableLooper.processAllMessages(); + verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + anyBoolean(), anyFloat(), anyFloat(), eq(null)); + + mDozeSensors.requestTemporaryDisable(); + reset(mCallback); + mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); + mTestableLooper.processAllMessages(); + verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + anyBoolean(), anyFloat(), anyFloat(), eq(null)); + } + + private class TestableDozeSensors extends DozeSensors { + + TestableDozeSensors() { + super(getContext(), mAlarmManager, mSensorManager, mDozeParameters, + mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, + mAlwaysOnDisplayPolicy); + for (TriggerSensor sensor : mSensors) { + if (sensor instanceof PluginSensor + && ((PluginSensor) sensor).mPluginSensor.getType() + == TYPE_WAKE_LOCK_SCREEN) { + mWakeLockScreenListener = (PluginSensor) sensor; + } + } + } + } +} |