Allow in-progress touch sessions to continue outside resume. am: f296aa6cea

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22133031

Change-Id: Id7d59f50d1614ccb8d6bd7b6a53855f1c96b85c2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Bryce Lee
2023-04-02 03:55:27 +00:00
committed by Automerger Merge Worker
2 changed files with 81 additions and 5 deletions

View File

@@ -101,6 +101,10 @@ public class DreamOverlayTouchMonitor {
completer.set(predecessor);
}
if (mActiveTouchSessions.isEmpty() && mStopMonitoringPending) {
stopMonitoring(false);
}
});
return "DreamOverlayTouchMonitor::pop";
@@ -214,7 +218,12 @@ public class DreamOverlayTouchMonitor {
@Override
public void onPause(@NonNull LifecycleOwner owner) {
stopMonitoring();
stopMonitoring(false);
}
@Override
public void onDestroy(LifecycleOwner owner) {
stopMonitoring(true);
}
};
@@ -222,7 +231,7 @@ public class DreamOverlayTouchMonitor {
* When invoked, instantiates a new {@link InputSession} to monitor touch events.
*/
private void startMonitoring() {
stopMonitoring();
stopMonitoring(true);
mCurrentInputSession = mInputSessionFactory.create(
"dreamOverlay",
mInputEventListener,
@@ -234,11 +243,16 @@ public class DreamOverlayTouchMonitor {
/**
* Destroys any active {@link InputSession}.
*/
private void stopMonitoring() {
private void stopMonitoring(boolean force) {
if (mCurrentInputSession == null) {
return;
}
if (!mActiveTouchSessions.isEmpty() && !force) {
mStopMonitoringPending = true;
return;
}
// When we stop monitoring touches, we must ensure that all active touch sessions and
// descendants informed of the removal so any cleanup for active tracking can proceed.
mExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
@@ -250,6 +264,7 @@ public class DreamOverlayTouchMonitor {
mCurrentInputSession.dispose();
mCurrentInputSession = null;
mStopMonitoringPending = false;
}
@@ -257,6 +272,8 @@ public class DreamOverlayTouchMonitor {
private final Collection<DreamTouchHandler> mHandlers;
private final DisplayHelper mDisplayHelper;
private boolean mStopMonitoringPending;
private InputChannelCompat.InputEventListener mInputEventListener =
new InputChannelCompat.InputEventListener() {
@Override

View File

@@ -399,7 +399,21 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
}
@Test
public void testPause() {
public void testPauseWithNoActiveSessions() {
final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
final Environment environment = new Environment(Stream.of(touchHandler)
.collect(Collectors.toCollection(HashSet::new)));
environment.updateLifecycle(observerOwnerPair -> {
observerOwnerPair.first.onPause(observerOwnerPair.second);
});
environment.verifyInputSessionDispose();
}
@Test
public void testDeferredPauseWithActiveSessions() {
final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
final Environment environment = new Environment(Stream.of(touchHandler)
@@ -417,13 +431,58 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
environment.publishInputEvent(event);
verify(eventListener).onInputEvent(eq(event));
final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor =
ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class);
verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture());
environment.updateLifecycle(observerOwnerPair -> {
observerOwnerPair.first.onPause(observerOwnerPair.second);
});
verify(environment.mInputSession, never()).dispose();
// End session
touchSessionArgumentCaptor.getValue().pop();
environment.executeAll();
// Check to make sure the input session is now disposed.
environment.verifyInputSessionDispose();
}
@Test
public void testDestroyWithActiveSessions() {
final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
final Environment environment = new Environment(Stream.of(touchHandler)
.collect(Collectors.toCollection(HashSet::new)));
final InputEvent initialEvent = Mockito.mock(InputEvent.class);
environment.publishInputEvent(initialEvent);
// Ensure session started
final InputChannelCompat.InputEventListener eventListener =
registerInputEventListener(touchHandler);
// First event will be missed since we register after the execution loop,
final InputEvent event = Mockito.mock(InputEvent.class);
environment.publishInputEvent(event);
verify(eventListener).onInputEvent(eq(event));
final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor =
ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class);
verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture());
environment.updateLifecycle(observerOwnerPair -> {
observerOwnerPair.first.onDestroy(observerOwnerPair.second);
});
// Check to make sure the input session is now disposed.
environment.verifyInputSessionDispose();
}
@Test
public void testPilfering() {
final DreamTouchHandler touchHandler1 = Mockito.mock(DreamTouchHandler.class);
@@ -476,7 +535,7 @@ public class DreamOverlayTouchMonitorTest extends SysuiTestCase {
environment.executeAll();
environment.updateLifecycle(observerOwnerPair -> {
observerOwnerPair.first.onPause(observerOwnerPair.second);
observerOwnerPair.first.onDestroy(observerOwnerPair.second);
});
environment.executeAll();