summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt80
2 files changed, 85 insertions, 4 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 40737120f364..0b86d1dbbc58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -138,7 +138,11 @@ class DragResizeInputListener implements AutoCloseable {
mHandler = handler;
mChoreographer = choreographer;
mDisplayId = displayId;
- mDecorationSurface = decorationSurface;
+ // Creates a new SurfaceControl pointing the same underlying surface with decorationSurface
+ // to ensure that mDecorationSurface will not be released while it's used on the background
+ // thread. Note that the empty name will be overridden by the next copyFrom call.
+ mDecorationSurface = surfaceControlBuilderSupplier.get().setName("").build();
+ mDecorationSurface.copyFrom(decorationSurface, "DragResizeInputListener");
mDragPositioningCallback = callback;
mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier;
mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
@@ -427,6 +431,9 @@ class DragResizeInputListener implements AutoCloseable {
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
+ // Removing this surface on the background thread to ensure that mInitInputChannels has
+ // already been finished.
+ mSurfaceControlTransactionSupplier.get().remove(mDecorationSurface).apply();
});
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
index e23d0ad55b04..360099777bde 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt
@@ -40,11 +40,13 @@ import com.android.wm.shell.windowdecor.DragResizeInputListener.TaskResizeInputE
import com.google.common.truth.Truth.assertThat
import java.util.function.Consumer
import java.util.function.Supplier
+import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.argThat
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
@@ -65,6 +67,13 @@ class DragResizeInputListenerTest : ShellTestCase() {
private val mockInputEventReceiver = mock<TaskResizeInputEventReceiver>()
private val inputChannel = mock<InputChannel>()
private val sinkInputChannel = mock<InputChannel>()
+ private val decorationSurface = SurfaceControl.Builder().setName("decoration surface").build()
+ private val createdSurfaces = ArrayList<SurfaceControl>()
+
+ @After
+ fun tearDown() {
+ decorationSurface.release()
+ }
@Test
fun testGrantInputChannelOffMainThread() {
@@ -75,6 +84,35 @@ class DragResizeInputListenerTest : ShellTestCase() {
}
@Test
+ fun testGrantInputChannelAfterDecorSurfaceReleased() {
+ // Keep tracking the underlying surface that the decorationSurface points to.
+ val forVerification = SurfaceControl(decorationSurface, "forVerification")
+ try {
+ create()
+ decorationSurface.release()
+ testBgExecutor.flushAll()
+
+ verify(mockWindowSession)
+ .grantInputChannel(
+ anyInt(),
+ argThat<SurfaceControl> { isValid && isSameSurface(forVerification) },
+ any(),
+ anyOrNull(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyOrNull(),
+ any(),
+ any(),
+ any(),
+ )
+ } finally {
+ forVerification.release()
+ }
+ }
+
+ @Test
fun testInitializationCallback_waitsForBgSetup() {
val inputListener = create()
@@ -155,6 +193,30 @@ class DragResizeInputListenerTest : ShellTestCase() {
verify(sinkInputChannel).dispose()
}
+ @Test
+ fun testClose_beforeBgSetup_releaseSurfaces() {
+ val inputListener = create()
+ inputListener.close()
+ testBgExecutor.flushAll()
+ testMainExecutor.flushAll()
+
+ assertThat(createdSurfaces).hasSize(1)
+ assertThat(createdSurfaces[0].isValid).isFalse()
+ }
+
+ @Test
+ fun testClose_afterBgSetup_releaseSurfaces() {
+ val inputListener = create()
+ testBgExecutor.flushAll()
+ inputListener.close()
+ testMainExecutor.flushAll()
+ testBgExecutor.flushAll()
+
+ assertThat(createdSurfaces).hasSize(2)
+ assertThat(createdSurfaces[0].isValid).isFalse()
+ assertThat(createdSurfaces[1].isValid).isFalse()
+ }
+
private fun verifyNoInputChannelGrantRequests() {
verify(mockWindowSession, never())
.grantInputChannel(
@@ -184,10 +246,22 @@ class DragResizeInputListenerTest : ShellTestCase() {
TestHandler(Looper.getMainLooper()),
mock<Choreographer>(),
Display.DEFAULT_DISPLAY,
- mock<SurfaceControl>(),
+ decorationSurface,
mock<DragPositioningCallback>(),
- { SurfaceControl.Builder() },
- { StubTransaction() },
+ {
+ object : SurfaceControl.Builder() {
+ override fun build(): SurfaceControl {
+ return super.build().also { createdSurfaces.add(it) }
+ }
+ }
+ },
+ {
+ object : StubTransaction() {
+ override fun remove(sc: SurfaceControl): SurfaceControl.Transaction {
+ return super.remove(sc).also { sc.release() }
+ }
+ }
+ },
mock<DisplayController>(),
mock<DesktopModeEventLogger>(),
inputChannel,