From f6a0990432aadc071e9ee8c702df599d648324a2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 8 Jun 2017 18:17:34 -0700 Subject: [PATCH] Final fixes for Android O pointer capture --- app/src/main/java/com/limelight/Game.java | 42 ++++++++++++------- .../AndroidNativePointerCaptureProvider.java | 2 +- .../input/capture/InputCaptureManager.java | 15 ++++--- .../input/capture/InputCaptureProvider.java | 6 ++- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 7cb81795..31001e7b 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -170,20 +170,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, streamView = (StreamView) findViewById(R.id.surfaceView); streamView.setOnGenericMotionListener(this); streamView.setOnTouchListener(this); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - streamView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - inputCaptureProvider.enableCapture(); - } - }); - streamView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() { - @Override - public boolean onCapturedPointer(View view, MotionEvent motionEvent) { - return handleMotionEvent(motionEvent); - } - }); - } // Warn the user if they're on a metered connection checkDataConnection(); @@ -273,6 +259,18 @@ public class Game extends Activity implements SurfaceHolder.Callback, inputCaptureProvider = InputCaptureManager.getInputCaptureProvider(this, this); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // The view must be focusable for pointer capture to work. + streamView.setFocusable(true); + streamView.setDefaultFocusHighlightEnabled(false); + streamView.setOnCapturedPointerListener(new View.OnCapturedPointerListener() { + @Override + public boolean onCapturedPointer(View view, MotionEvent motionEvent) { + return handleMotionEvent(motionEvent); + } + }); + } + if (prefConfig.onscreenController) { // create virtual onscreen controller virtualController = new VirtualController(conn, @@ -291,6 +289,20 @@ public class Game extends Activity implements SurfaceHolder.Callback, streamView.getHolder().addCallback(this); } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Capture is lost when focus is lost, so it must be requested again + // when focus is regained. + if (inputCaptureProvider.isCapturingEnabled() && hasFocus) { + // Recapture the pointer if focus was regained + streamView.requestPointerCapture(); + } + } + } + private void prepareDisplayForRendering() { Display display = getWindowManager().getDefaultDisplay(); WindowManager.LayoutParams windowLayoutParams = getWindow().getAttributes(); @@ -699,7 +711,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, int changedButtons = event.getButtonState() ^ lastButtonState; // Ignore mouse input if we're not capturing from our input source - if (!inputCaptureProvider.isCapturing()) { + if (!inputCaptureProvider.isCapturingActive()) { return false; } 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 d2b16ae3..59c0f29a 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 @@ -32,7 +32,7 @@ public class AndroidNativePointerCaptureProvider extends InputCaptureProvider { } @Override - public boolean isCapturing() { + public boolean isCapturingActive() { return targetView.hasPointerCapture(); } 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 320968ff..022a5aef 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 @@ -9,22 +9,21 @@ import com.limelight.binding.input.evdev.EvdevListener; public class InputCaptureManager { public static InputCaptureProvider getInputCaptureProvider(Activity activity, EvdevListener rootListener) { - // Shield capture is preferred because it can capture when the cursor is over - // the system UI. Android N native capture can only capture over views owned - // by the application. - if (ShieldCaptureProvider.isCaptureProviderSupported()) { - LimeLog.info("Using NVIDIA mouse capture extension"); - return new ShieldCaptureProvider(activity); - } - else if (AndroidNativePointerCaptureProvider.isCaptureProviderSupported()) { + if (AndroidNativePointerCaptureProvider.isCaptureProviderSupported()) { LimeLog.info("Using Android O+ native mouse capture"); return new AndroidNativePointerCaptureProvider(activity.findViewById(R.id.surfaceView)); } + else if (ShieldCaptureProvider.isCaptureProviderSupported()) { + LimeLog.info("Using NVIDIA mouse capture extension"); + return new ShieldCaptureProvider(activity); + } else if (EvdevCaptureProvider.isCaptureProviderSupported()) { LimeLog.info("Using Evdev mouse capture"); return new EvdevCaptureProvider(activity, rootListener); } else if (AndroidPointerIconCaptureProvider.isCaptureProviderSupported()) { + // Android N's native capture can't capture over system UI elements + // so we want to only use it if there's no other option. LimeLog.info("Using Android N+ pointer hiding"); return new AndroidPointerIconCaptureProvider(activity); } diff --git a/app/src/main/java/com/limelight/binding/input/capture/InputCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/capture/InputCaptureProvider.java index cea2bd61..fb35aeae 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/InputCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/capture/InputCaptureProvider.java @@ -14,7 +14,11 @@ public abstract class InputCaptureProvider { public void destroy() {} - public boolean isCapturing() { + public boolean isCapturingEnabled() { + return isCapturing; + } + + public boolean isCapturingActive() { return isCapturing; }