Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b60ee9e6 authored by Asmita Poddar's avatar Asmita Poddar
Browse files

Ensure that VirtualMouse creation is complete before usage

Use Thread.join for waiting for the virtual mouse creation to complete
before calling methods using the virtual mouse.
This approach blocks the calling thread only if the virtual mouse creation thread
is still running, and returns immediately if the thread has already completed.
This will also fix test flakiness, which were failing due to
VirtualMouse not being available yet.

Bug: 356262422
Test: atest FrameworksServicesTests:MouseKeysInterceptorTest --iterations 300
Flag: TEST_ONLY
Change-Id: I5bbbcad565dcfb5c8c71b1241828aaa005d185e0
parent 7ef1ce6e
Loading
Loading
Loading
Loading
+39 −24
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
    private final AccessibilityManagerService mAms;
    private final Handler mHandler;

    /** Thread to wait for virtual mouse creation to complete */
    private final Thread mCreateVirtualMouseThread;

    VirtualDeviceManager.VirtualDevice mVirtualDevice = null;

    private VirtualMouse mVirtualMouse = null;
@@ -154,35 +157,48 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
        mHandler = new Handler(looper, this);
        // Create the virtual mouse on a separate thread since virtual device creation
        // should happen on an auxiliary thread, and not from the handler's thread.
        // This is because virtual device creation is a blocking operation and can cause a
        // deadlock if it is called from the handler's thread.
        new Thread(() -> {
        // This is because the handler thread is the same as the main thread,
        // and the main thread will be blocked waiting for the virtual device to be created.
        mCreateVirtualMouseThread = new Thread(() -> {
            mVirtualMouse = createVirtualMouse(displayId);
        }).start();
        });
        mCreateVirtualMouseThread.start();
    }

    /**
     * Wait for {@code mVirtualMouse} to be created.
     * This will ensure that {@code mVirtualMouse} is always created before
     * trying to send mouse events.
     **/
    private void waitForVirtualMouseCreation() {
        try {
            // Block the current thread until the virtual mouse creation thread completes.
            mCreateVirtualMouseThread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
    }

    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    private void sendVirtualMouseRelativeEvent(float x, float y) {
        if (mVirtualMouse != null) {
        waitForVirtualMouseCreation();
        mVirtualMouse.sendRelativeEvent(new VirtualMouseRelativeEvent.Builder()
                .setRelativeX(x)
                .setRelativeY(y)
                .build()
        );
    }
    }

    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    private void sendVirtualMouseButtonEvent(int buttonCode, int actionCode) {
        if (mVirtualMouse != null) {
        waitForVirtualMouseCreation();
        mVirtualMouse.sendButtonEvent(new VirtualMouseButtonEvent.Builder()
                .setAction(actionCode)
                .setButtonCode(buttonCode)
                .build()
        );
    }
    }

    /**
     * Performs a mouse scroll action based on the provided key code.
@@ -205,12 +221,11 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation
            case DOWN_MOVE_OR_SCROLL -> -1.0f;
            default -> 0.0f;
        };
        if (mVirtualMouse != null) {
        waitForVirtualMouseCreation();
        mVirtualMouse.sendScrollEvent(new VirtualMouseScrollEvent.Builder()
                .setYAxisMovement(y)
                .build()
        );
        }
        if (DEBUG) {
            Slog.d(LOG_TAG, "Performed mouse key event: " + mouseKeyEvent.name()
                    + " for scroll action with axis movement (y=" + y + ")");
+0 −4
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import java.util.concurrent.TimeUnit
import java.util.LinkedList
import java.util.Queue
import android.util.ArraySet
@@ -117,9 +116,6 @@ class MouseKeysInterceptorTest {
        Mockito.`when`(mockAms.traceManager).thenReturn(mockTraceManager)

        mouseKeysInterceptor = MouseKeysInterceptor(mockAms, testLooper.looper, DISPLAY_ID)
        // VirtualMouse is created on a separate thread.
        // Wait for VirtualMouse to be created before running tests
        TimeUnit.MILLISECONDS.sleep(20L)
        mouseKeysInterceptor.next = nextInterceptor
    }