Merge "Prevent recursive calls to proximity sensor." into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-05-19 15:24:46 +00:00
committed by Android (Google) Code Review
9 changed files with 161 additions and 31 deletions

View File

@@ -34,6 +34,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -56,6 +57,7 @@ public class DozeFactory {
private final ProximitySensor mProximitySensor;
private final DelayedWakeLock.Builder mDelayedWakeLockBuilder;
private final Handler mHandler;
private final DelayableExecutor mDelayableExecutor;
private final BiometricUnlockController mBiometricUnlockController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final DozeHost mDozeHost;
@@ -68,6 +70,7 @@ public class DozeFactory {
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
@@ -83,6 +86,7 @@ public class DozeFactory {
mProximitySensor = proximitySensor;
mDelayedWakeLockBuilder = delayedWakeLockBuilder;
mHandler = handler;
mDelayableExecutor = delayableExecutor;
mBiometricUnlockController = biometricUnlockController;
mBroadcastDispatcher = broadcastDispatcher;
mDozeHost = dozeHost;
@@ -107,8 +111,8 @@ public class DozeFactory {
new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
new DozeFalsingManagerAdapter(mFalsingManager),
createDozeTriggers(dozeService, mAsyncSensorManager, mDozeHost,
mAlarmManager, config, mDozeParameters, mHandler, wakeLock, machine,
mDockManager, mDozeLog),
mAlarmManager, config, mDozeParameters, mDelayableExecutor, wakeLock,
machine, mDockManager, mDozeLog),
createDozeUi(dozeService, mDozeHost, wakeLock, machine, mHandler,
mAlarmManager, mDozeParameters, mDozeLog),
new DozeScreenState(wrappedService, mHandler, mDozeHost, mDozeParameters,
@@ -135,11 +139,11 @@ public class DozeFactory {
private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine,
DockManager dockManager, DozeLog dozeLog) {
DozeParameters params, DelayableExecutor delayableExecutor, WakeLock wakeLock,
DozeMachine machine, DockManager dockManager, DozeLog dozeLog) {
boolean allowPulseTriggers = true;
return new DozeTriggers(context, machine, host, alarmManager, config, params,
sensorManager, handler, wakeLock, allowPulseTriggers, dockManager,
sensorManager, delayableExecutor, wakeLock, allowPulseTriggers, dockManager,
mProximitySensor, dozeLog, mBroadcastDispatcher);
}

View File

@@ -101,7 +101,8 @@ public class DozeSensors {
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog) {
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
ProximitySensor proximitySensor) {
mContext = context;
mAlarmManager = alarmManager;
mSensorManager = sensorManager;
@@ -111,6 +112,7 @@ public class DozeSensors {
mProxCallback = proxCallback;
mResolver = mContext.getContentResolver();
mCallback = callback;
mProximitySensor = proximitySensor;
boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
mSensors = new TriggerSensor[] {
@@ -173,7 +175,6 @@ public class DozeSensors {
dozeLog),
};
mProximitySensor = new ProximitySensor(context.getResources(), sensorManager);
setProxListening(false); // Don't immediately start listening when we register.
mProximitySensor.register(
proximityEvent -> {

View File

@@ -26,7 +26,6 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.Formatter;
@@ -43,6 +42,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
@@ -152,9 +152,9 @@ public class DozeTriggers implements DozeMachine.Part {
public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
AlarmManager alarmManager, AmbientDisplayConfiguration config,
DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
ProximitySensor proximitySensor,
DozeParameters dozeParameters, AsyncSensorManager sensorManager,
DelayableExecutor delayableExecutor, WakeLock wakeLock, boolean allowPulseTriggers,
DockManager dockManager, ProximitySensor proximitySensor,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
mContext = context;
mMachine = machine;
@@ -165,10 +165,10 @@ public class DozeTriggers implements DozeMachine.Part {
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog);
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mDockManager = dockManager;
mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, delayableExecutor);
mDozeLog = dozeLog;
mBroadcastDispatcher = broadcastDispatcher;
}

View File

@@ -21,16 +21,17 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -49,8 +50,9 @@ public class ProximitySensor {
private String mTag = null;
@VisibleForTesting ProximityEvent mLastEvent;
private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;
private boolean mPaused;
@VisibleForTesting protected boolean mPaused;
private boolean mRegistered;
private final AtomicBoolean mAlerting = new AtomicBoolean();
private SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
@@ -217,8 +219,12 @@ public class ProximitySensor {
/** Update all listeners with the last value this class received from the sensor. */
public void alertListeners() {
if (mAlerting.getAndSet(true)) {
return;
}
mListeners.forEach(proximitySensorListener ->
proximitySensorListener.onSensorEvent(mLastEvent));
mAlerting.set(false);
}
private void onSensorEvent(SensorEvent event) {
@@ -239,14 +245,14 @@ public class ProximitySensor {
public static class ProximityCheck implements Runnable {
private final ProximitySensor mSensor;
private final Handler mHandler;
private final DelayableExecutor mDelayableExecutor;
private List<Consumer<Boolean>> mCallbacks = new ArrayList<>();
@Inject
public ProximityCheck(ProximitySensor sensor, Handler handler) {
public ProximityCheck(ProximitySensor sensor, DelayableExecutor delayableExecutor) {
mSensor = sensor;
mSensor.setTag("prox_check");
mHandler = handler;
mDelayableExecutor = delayableExecutor;
mSensor.pause();
ProximitySensorListener listener = proximityEvent -> {
mCallbacks.forEach(
@@ -280,7 +286,7 @@ public class ProximitySensor {
mCallbacks.add(callback);
if (!mSensor.isRegistered()) {
mSensor.resume();
mHandler.postDelayed(this, timeoutMs);
mDelayableExecutor.executeDelayed(this, timeoutMs);
}
}
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -46,6 +47,7 @@ import com.android.systemui.doze.DozeSensors.TriggerSensor;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
import org.junit.Before;
@@ -82,7 +84,7 @@ public class DozeSensorsTest extends SysuiTestCase {
@Mock
private DozeLog mDozeLog;
@Mock
private Sensor mProximitySensor;
private ProximitySensor mProximitySensor;
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
private TestableLooper mTestableLooper;
private DozeSensors mDozeSensors;
@@ -93,7 +95,6 @@ public class DozeSensorsTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(mProximitySensor);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -103,10 +104,9 @@ public class DozeSensorsTest extends SysuiTestCase {
@Test
public void testRegisterProx() {
// We should not register with the sensor manager initially.
verify(mSensorManager, never()).registerListener(any(), any(Sensor.class), anyInt());
assertFalse(mProximitySensor.isRegistered());
mDozeSensors.setProxListening(true);
verify(mSensorManager).registerListener(any(), any(Sensor.class), anyInt());
verify(mProximitySensor).resume();
}
@Test
@@ -169,7 +169,8 @@ public class DozeSensorsTest extends SysuiTestCase {
TestableDozeSensors() {
super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog);
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
mProximitySensor);
for (TriggerSensor sensor : mSensors) {
if (sensor instanceof PluginSensor
&& ((PluginSensor) sensor).mPluginSensor.getType()

View File

@@ -31,7 +31,6 @@ import android.app.AlarmManager;
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -42,10 +41,12 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeProximitySensor;
import com.android.systemui.util.sensors.FakeSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -75,6 +76,7 @@ public class DozeTriggersTest extends SysuiTestCase {
private FakeSensorManager mSensors;
private Sensor mTapSensor;
private FakeProximitySensor mProximitySensor;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setUp() throws Exception {
@@ -89,7 +91,7 @@ public class DozeTriggersTest extends SysuiTestCase {
mProximitySensor = new FakeProximitySensor(getContext().getResources(), asyncSensorManager);
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
asyncSensorManager, mFakeExecutor, wakeLock, true,
mDockManager, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
waitForSensorManager();
}
@@ -111,9 +113,8 @@ public class DozeTriggersTest extends SysuiTestCase {
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
waitForSensorManager();
mProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(false, 2));
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
mProximitySensor.alertListeners();
verify(mMachine).requestPulse(anyInt());

View File

@@ -20,6 +20,7 @@ import android.content.res.Resources;
public class FakeProximitySensor extends ProximitySensor {
private boolean mAvailable;
private boolean mRegistered;
public FakeProximitySensor(Resources resources, AsyncSensorManager sensorManager) {
super(resources, sensorManager);
@@ -34,6 +35,11 @@ public class FakeProximitySensor extends ProximitySensor {
mLastEvent = event;
}
@Override
public boolean isRegistered() {
return mRegistered;
}
@Override
public boolean getSensorAvailable() {
return mAvailable;
@@ -41,11 +47,11 @@ public class FakeProximitySensor extends ProximitySensor {
@Override
protected void registerInternal() {
// no-op
mRegistered = !mPaused;
}
@Override
protected void unregisterInternal() {
// no-op
mRegistered = false;
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2020 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.util.sensors;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.function.Consumer;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ProximityCheckTest extends SysuiTestCase {
private FakeProximitySensor mFakeProximitySensor;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private TestableCallback mTestableCallback = new TestableCallback();
private ProximitySensor.ProximityCheck mProximityCheck;
@Before
public void setUp() throws Exception {
AsyncSensorManager asyncSensorManager =
new AsyncSensorManager(new FakeSensorManager(mContext), null, new Handler());
mFakeProximitySensor = new FakeProximitySensor(mContext.getResources(), asyncSensorManager);
mProximityCheck = new ProximitySensor.ProximityCheck(mFakeProximitySensor, mFakeExecutor);
}
@Test
public void testCheck() {
mProximityCheck.check(100, mTestableCallback);
assertNull(mTestableCallback.mLastResult);
mFakeProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(true, 0));
mFakeProximitySensor.alertListeners();
assertTrue(mTestableCallback.mLastResult);
}
@Test
public void testTimeout() {
mProximityCheck.check(100, mTestableCallback);
assertTrue(mFakeProximitySensor.isRegistered());
mFakeExecutor.advanceClockToNext();
mFakeExecutor.runAllReady();
assertFalse(mFakeProximitySensor.isRegistered());
}
private static class TestableCallback implements Consumer<Boolean> {
Boolean mLastResult;
@Override
public void accept(Boolean result) {
mLastResult = result;
}
}
}

View File

@@ -219,6 +219,26 @@ public class ProximitySensorTest extends SysuiTestCase {
waitForSensorManager();
}
@Test
public void testPreventRecursiveAlert() {
TestableListener listenerA = new TestableListener() {
@Override
public void onSensorEvent(ProximitySensor.ProximityEvent proximityEvent) {
super.onSensorEvent(proximityEvent);
if (mCallCount < 2) {
mProximitySensor.alertListeners();
}
}
};
mProximitySensor.register(listenerA);
mProximitySensor.alertListeners();
assertEquals(1, listenerA.mCallCount);
}
class TestableListener implements ProximitySensor.ProximitySensorListener {
ProximitySensor.ProximityEvent mLastEvent;
int mCallCount = 0;