From 16b845ab84fbad8a6fc3a7c4b3c1ff0f875bc6b6 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 19 Dec 2018 15:06:46 +0500 Subject: [PATCH] Hide the mouse cursor during pointer capture to work around DeX bug --- .../AndroidNativePointerCaptureProvider.java | 24 +++++++++++++++++-- .../input/capture/InputCaptureManager.java | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/limelight/binding/input/capture/AndroidNativePointerCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/capture/AndroidNativePointerCaptureProvider.java index a93b1acd..1c404e58 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/AndroidNativePointerCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/capture/AndroidNativePointerCaptureProvider.java @@ -1,27 +1,46 @@ package com.limelight.binding.input.capture; import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; import android.os.Build; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.PointerIcon; import android.view.View; +import android.view.ViewGroup; @TargetApi(Build.VERSION_CODES.O) public class AndroidNativePointerCaptureProvider extends InputCaptureProvider { - + private Context context; private View targetView; + private ViewGroup rootViewGroup; - public AndroidNativePointerCaptureProvider(View targetView) { + public AndroidNativePointerCaptureProvider(Activity activity, View targetView) { + this.context = activity; this.targetView = targetView; + this.rootViewGroup = (ViewGroup) activity.getWindow().getDecorView(); } public static boolean isCaptureProviderSupported() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; } + // DeX on Android 8.1 doesn't properly hide the mouse pointer when running in + // windowed mode, even though the cursor is properly captured (and thus doesn't move anymore). + // To work around this issue, hide the pointer icon when requesting pointer capture. + private void setPointerIconOnAllViews(PointerIcon icon) { + for (int i = 0; i < rootViewGroup.getChildCount(); i++) { + View view = rootViewGroup.getChildAt(i); + view.setPointerIcon(icon); + } + rootViewGroup.setPointerIcon(icon); + } + @Override public void enableCapture() { super.enableCapture(); + setPointerIconOnAllViews(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_NULL)); targetView.requestPointerCapture(); } @@ -29,6 +48,7 @@ public class AndroidNativePointerCaptureProvider extends InputCaptureProvider { public void disableCapture() { super.disableCapture(); targetView.releasePointerCapture(); + setPointerIconOnAllViews(null); } @Override diff --git a/app/src/main/java/com/limelight/binding/input/capture/InputCaptureManager.java b/app/src/main/java/com/limelight/binding/input/capture/InputCaptureManager.java index d88eb5a7..472f3bc2 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/InputCaptureManager.java +++ b/app/src/main/java/com/limelight/binding/input/capture/InputCaptureManager.java @@ -12,7 +12,7 @@ public class InputCaptureManager { public static InputCaptureProvider getInputCaptureProvider(Activity activity, EvdevListener rootListener) { if (AndroidNativePointerCaptureProvider.isCaptureProviderSupported()) { LimeLog.info("Using Android O+ native mouse capture"); - return new AndroidNativePointerCaptureProvider(activity.findViewById(R.id.surfaceView)); + return new AndroidNativePointerCaptureProvider(activity, activity.findViewById(R.id.surfaceView)); } // LineageOS implemented broken NVIDIA capture extensions, so avoid using them on root builds. // See https://github.com/LineageOS/android_frameworks_base/commit/d304f478a023430f4712dbdc3ee69d9ad02cebd3