diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 63862a18..7cb81795 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -170,6 +170,20 @@ 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(); @@ -674,7 +688,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, return true; } } - else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) + else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0 || + event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) { // This case is for mice if (event.getSource() == InputDevice.SOURCE_MOUSE || @@ -683,6 +698,11 @@ 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()) { + return false; + } + if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) { // Send the vertical scroll packet byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL); 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 new file mode 100644 index 00000000..d2b16ae3 --- /dev/null +++ b/app/src/main/java/com/limelight/binding/input/capture/AndroidNativePointerCaptureProvider.java @@ -0,0 +1,53 @@ +package com.limelight.binding.input.capture; + +import android.annotation.TargetApi; +import android.os.Build; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.View; + +@TargetApi(Build.VERSION_CODES.O) +public class AndroidNativePointerCaptureProvider extends InputCaptureProvider { + + private View targetView; + + public AndroidNativePointerCaptureProvider(View targetView) { + this.targetView = targetView; + } + + public static boolean isCaptureProviderSupported() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; + } + + @Override + public void enableCapture() { + super.enableCapture(); + targetView.requestPointerCapture(); + } + + @Override + public void disableCapture() { + super.disableCapture(); + targetView.releasePointerCapture(); + } + + @Override + public boolean isCapturing() { + return targetView.hasPointerCapture(); + } + + @Override + public boolean eventHasRelativeMouseAxes(MotionEvent event) { + return event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE; + } + + @Override + public float getRelativeAxisX(MotionEvent event) { + return event.getX(); + } + + @Override + public float getRelativeAxisY(MotionEvent event) { + return event.getY(); + } +} diff --git a/app/src/main/java/com/limelight/binding/input/capture/AndroidCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/capture/AndroidPointerIconCaptureProvider.java similarity index 88% rename from app/src/main/java/com/limelight/binding/input/capture/AndroidCaptureProvider.java rename to app/src/main/java/com/limelight/binding/input/capture/AndroidPointerIconCaptureProvider.java index f1133512..6774bfdf 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/AndroidCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/capture/AndroidPointerIconCaptureProvider.java @@ -10,11 +10,11 @@ import android.view.View; import android.view.ViewGroup; @TargetApi(Build.VERSION_CODES.N) -public class AndroidCaptureProvider extends InputCaptureProvider { +public class AndroidPointerIconCaptureProvider extends InputCaptureProvider { private ViewGroup rootViewGroup; private Context context; - public AndroidCaptureProvider(Activity activity) { + public AndroidPointerIconCaptureProvider(Activity activity) { this.context = activity; this.rootViewGroup = (ViewGroup) activity.getWindow().getDecorView(); } @@ -33,11 +33,13 @@ public class AndroidCaptureProvider extends InputCaptureProvider { @Override public void enableCapture() { + super.enableCapture(); setPointerIconOnAllViews(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_NULL)); } @Override public void disableCapture() { + super.disableCapture(); setPointerIconOnAllViews(null); } 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 4a5f634b..320968ff 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 @@ -3,6 +3,7 @@ package com.limelight.binding.input.capture; import android.app.Activity; import com.limelight.LimeLog; +import com.limelight.R; import com.limelight.binding.input.evdev.EvdevCaptureProvider; import com.limelight.binding.input.evdev.EvdevListener; @@ -15,13 +16,17 @@ public class InputCaptureManager { LimeLog.info("Using NVIDIA mouse capture extension"); return new ShieldCaptureProvider(activity); } + else if (AndroidNativePointerCaptureProvider.isCaptureProviderSupported()) { + LimeLog.info("Using Android O+ native mouse capture"); + return new AndroidNativePointerCaptureProvider(activity.findViewById(R.id.surfaceView)); + } else if (EvdevCaptureProvider.isCaptureProviderSupported()) { LimeLog.info("Using Evdev mouse capture"); return new EvdevCaptureProvider(activity, rootListener); } - else if (AndroidCaptureProvider.isCaptureProviderSupported()) { - LimeLog.info("Using Android N+ native mouse capture"); - return new AndroidCaptureProvider(activity); + else if (AndroidPointerIconCaptureProvider.isCaptureProviderSupported()) { + LimeLog.info("Using Android N+ pointer hiding"); + return new AndroidPointerIconCaptureProvider(activity); } else { LimeLog.info("Mouse capture not available"); 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 3de18c37..cea2bd61 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 @@ -3,10 +3,21 @@ package com.limelight.binding.input.capture; import android.view.MotionEvent; public abstract class InputCaptureProvider { - public abstract void enableCapture(); - public abstract void disableCapture(); + protected boolean isCapturing; + + public void enableCapture() { + isCapturing = true; + } + public void disableCapture() { + isCapturing = false; + } + public void destroy() {} + public boolean isCapturing() { + return isCapturing; + } + public boolean eventHasRelativeMouseAxes(MotionEvent event) { return false; } diff --git a/app/src/main/java/com/limelight/binding/input/capture/NullCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/capture/NullCaptureProvider.java index 553816c0..d8d9cb80 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/NullCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/capture/NullCaptureProvider.java @@ -1,10 +1,4 @@ package com.limelight.binding.input.capture; -public class NullCaptureProvider extends InputCaptureProvider { - @Override - public void enableCapture() {} - - @Override - public void disableCapture() {} -} +public class NullCaptureProvider extends InputCaptureProvider {} diff --git a/app/src/main/java/com/limelight/binding/input/capture/ShieldCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/capture/ShieldCaptureProvider.java index 98bbf7da..64e67573 100644 --- a/app/src/main/java/com/limelight/binding/input/capture/ShieldCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/capture/ShieldCaptureProvider.java @@ -63,11 +63,13 @@ public class ShieldCaptureProvider extends InputCaptureProvider { @Override public void enableCapture() { + super.enableCapture(); setCursorVisibility(false); } @Override public void disableCapture() { + super.disableCapture(); setCursorVisibility(true); } diff --git a/app/src/main/java/com/limelight/binding/input/evdev/EvdevCaptureProvider.java b/app/src/main/java/com/limelight/binding/input/evdev/EvdevCaptureProvider.java index 8b60a2d1..47f8dd2a 100644 --- a/app/src/main/java/com/limelight/binding/input/evdev/EvdevCaptureProvider.java +++ b/app/src/main/java/com/limelight/binding/input/evdev/EvdevCaptureProvider.java @@ -221,6 +221,7 @@ public class EvdevCaptureProvider extends InputCaptureProvider { @Override public void enableCapture() { + super.enableCapture(); if (!started) { // Start the handler thread if it's our first time // capturing @@ -247,6 +248,7 @@ public class EvdevCaptureProvider extends InputCaptureProvider { @Override public void disableCapture() { + super.disableCapture(); // This may be called on the main thread runInNetworkSafeContextSynchronously(new Runnable() { @Override