diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 536469d0..6422dce3 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -95,7 +95,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, private int lastButtonState = 0; // Only 2 touches are supported - private Timer touchTimer; private final TouchContext[] touchContextMap = new TouchContext[2]; private long threeFingerDownTime = 0; @@ -479,15 +478,14 @@ public class Game extends Activity implements SurfaceHolder.Callback, inputManager.registerInputDeviceListener(keyboardTranslator, null); // Initialize touch contexts - touchTimer = new Timer("TouchTimer", true); for (int i = 0; i < touchContextMap.length; i++) { if (!prefConfig.touchscreenTrackpad) { - touchContextMap[i] = new AbsoluteTouchContext(conn, i, streamView, touchTimer); + touchContextMap[i] = new AbsoluteTouchContext(conn, i, streamView); } else { touchContextMap[i] = new RelativeTouchContext(conn, i, REFERENCE_HORIZ_RES, REFERENCE_VERT_RES, - streamView, prefConfig, touchTimer); + streamView, prefConfig); } } @@ -1031,10 +1029,6 @@ public class Game extends Activity implements SurfaceHolder.Callback, protected void onDestroy() { super.onDestroy(); - if (touchTimer != null) { - touchTimer.cancel(); - } - InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); if (controllerHandler != null) { inputManager.unregisterInputDeviceListener(controllerHandler); diff --git a/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java b/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java index 89ffff70..d5fb4708 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java +++ b/app/src/main/java/com/limelight/binding/input/touch/AbsoluteTouchContext.java @@ -7,9 +7,6 @@ import android.view.View; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.MouseButtonPacket; -import java.util.Timer; -import java.util.TimerTask; - public class AbsoluteTouchContext implements TouchContext { private int lastTouchDownX = 0; private int lastTouchDownY = 0; @@ -22,13 +19,33 @@ public class AbsoluteTouchContext implements TouchContext { private boolean cancelled; private boolean confirmedLongPress; private boolean confirmedTap; - private TimerTask longPressTimerTask; - private TimerTask tapDownTimerTask; + + private final Runnable longPressRunnable = new Runnable() { + @Override + public void run() { + // This timer should have already expired, but cancel it just in case + cancelTapDownTimer(); + + // Switch from a left click to a right click after a long press + confirmedLongPress = true; + if (confirmedTap) { + conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT); + } + conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT); + } + }; + + private final Runnable tapDownRunnable = new Runnable() { + @Override + public void run() { + // Start our tap + tapConfirmed(); + } + }; private final NvConnection conn; private final int actionIndex; private final View targetView; - private final Timer timer; private final Handler handler; private final Runnable leftButtonUpRunnable = new Runnable() { @@ -49,12 +66,11 @@ public class AbsoluteTouchContext implements TouchContext { private static final int TOUCH_DOWN_DEAD_ZONE_TIME_THRESHOLD = 100; private static final int TOUCH_DOWN_DEAD_ZONE_DISTANCE_THRESHOLD = 20; - public AbsoluteTouchContext(NvConnection conn, int actionIndex, View view, Timer timer) + public AbsoluteTouchContext(NvConnection conn, int actionIndex, View view) { this.conn = conn; this.actionIndex = actionIndex; this.targetView = view; - this.timer = timer; this.handler = new Handler(Looper.getMainLooper()); } @@ -138,69 +154,22 @@ public class AbsoluteTouchContext implements TouchContext { lastTouchUpTime = eventTime; } - private synchronized void startLongPressTimer() { + private void startLongPressTimer() { cancelLongPressTimer(); - longPressTimerTask = new TimerTask() { - @Override - public void run() { - synchronized (AbsoluteTouchContext.this) { - // Check if someone cancelled us - if (longPressTimerTask == null) { - return; - } - - // Uncancellable now - longPressTimerTask = null; - - // This timer should have already expired, but cancel it just in case - cancelTapDownTimer(); - - // Switch from a left click to a right click after a long press - confirmedLongPress = true; - if (confirmedTap) { - conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT); - } - conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT); - } - } - }; - timer.schedule(longPressTimerTask, LONG_PRESS_TIME_THRESHOLD); + handler.postDelayed(longPressRunnable, LONG_PRESS_TIME_THRESHOLD); } - private synchronized void cancelLongPressTimer() { - if (longPressTimerTask != null) { - longPressTimerTask.cancel(); - longPressTimerTask = null; - } + private void cancelLongPressTimer() { + handler.removeCallbacks(longPressRunnable); } - private synchronized void startTapDownTimer() { + private void startTapDownTimer() { cancelTapDownTimer(); - tapDownTimerTask = new TimerTask() { - @Override - public void run() { - synchronized (AbsoluteTouchContext.this) { - // Check if someone cancelled us - if (tapDownTimerTask == null) { - return; - } - - // Uncancellable now - tapDownTimerTask = null; - - // Start our tap - tapConfirmed(); - } - } - }; - timer.schedule(tapDownTimerTask, TOUCH_DOWN_DEAD_ZONE_TIME_THRESHOLD); + handler.postDelayed(tapDownRunnable, TOUCH_DOWN_DEAD_ZONE_TIME_THRESHOLD); } - private synchronized void cancelTapDownTimer() { - if (tapDownTimerTask != null) { - tapDownTimerTask.cancel(); - tapDownTimerTask = null; - } + private void cancelTapDownTimer() { + handler.removeCallbacks(tapDownRunnable); } private void tapConfirmed() { diff --git a/app/src/main/java/com/limelight/binding/input/touch/RelativeTouchContext.java b/app/src/main/java/com/limelight/binding/input/touch/RelativeTouchContext.java index b5a4ecdf..7ed8f096 100644 --- a/app/src/main/java/com/limelight/binding/input/touch/RelativeTouchContext.java +++ b/app/src/main/java/com/limelight/binding/input/touch/RelativeTouchContext.java @@ -8,9 +8,6 @@ import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.MouseButtonPacket; import com.limelight.preferences.PreferenceConfiguration; -import java.util.Timer; -import java.util.TimerTask; - public class RelativeTouchContext implements TouchContext { private int lastTouchX = 0; private int lastTouchY = 0; @@ -21,7 +18,6 @@ public class RelativeTouchContext implements TouchContext { private boolean confirmedMove; private boolean confirmedDrag; private boolean confirmedScroll; - private TimerTask dragTimerTask; private double distanceMoved; private double xFactor, yFactor; private int pointerCount; @@ -33,9 +29,27 @@ public class RelativeTouchContext implements TouchContext { private final int referenceHeight; private final View targetView; private final PreferenceConfiguration prefConfig; - private final Timer timer; private final Handler handler; + private final Runnable dragTimerRunnable = new Runnable() { + @Override + public void run() { + // Check if someone already set move + if (confirmedMove) { + return; + } + + // The drag should only be processed for the primary finger + if (actionIndex != maxPointerCountInGesture - 1) { + return; + } + + // We haven't been cancelled before the timer expired so begin dragging + confirmedDrag = true; + conn.sendMouseButtonDown(getMouseButtonIndex()); + } + }; + // Indexed by MouseButtonPacket.BUTTON_XXX - 1 private final Runnable[] buttonUpRunnables = new Runnable[] { new Runnable() { @@ -79,8 +93,7 @@ public class RelativeTouchContext implements TouchContext { public RelativeTouchContext(NvConnection conn, int actionIndex, int referenceWidth, int referenceHeight, - View view, PreferenceConfiguration prefConfig, - Timer timer) + View view, PreferenceConfiguration prefConfig) { this.conn = conn; this.actionIndex = actionIndex; @@ -88,7 +101,6 @@ public class RelativeTouchContext implements TouchContext { this.referenceHeight = referenceHeight; this.targetView = view; this.prefConfig = prefConfig; - this.timer = timer; this.handler = new Handler(Looper.getMainLooper()); } @@ -187,47 +199,16 @@ public class RelativeTouchContext implements TouchContext { } } - private synchronized void startDragTimer() { + private void startDragTimer() { cancelDragTimer(); - dragTimerTask = new TimerTask() { - @Override - public void run() { - synchronized (RelativeTouchContext.this) { - // Check if someone already set move - if (confirmedMove) { - return; - } - - // The drag should only be processed for the primary finger - if (actionIndex != maxPointerCountInGesture - 1) { - return; - } - - // Check if someone cancelled us - if (dragTimerTask == null) { - return; - } - - // Uncancellable now - dragTimerTask = null; - - // We haven't been cancelled before the timer expired so begin dragging - confirmedDrag = true; - conn.sendMouseButtonDown(getMouseButtonIndex()); - } - } - }; - timer.schedule(dragTimerTask, DRAG_TIME_THRESHOLD); + handler.postDelayed(dragTimerRunnable, DRAG_TIME_THRESHOLD); } - private synchronized void cancelDragTimer() { - if (dragTimerTask != null) { - dragTimerTask.cancel(); - dragTimerTask = null; - } + private void cancelDragTimer() { + handler.removeCallbacks(dragTimerRunnable); } - private synchronized void checkForConfirmedMove(int eventX, int eventY) { + private void checkForConfirmedMove(int eventX, int eventY) { // If we've already confirmed something, get out now if (confirmedMove || confirmedDrag) { return; diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalButton.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalButton.java index 6cbd792e..9ceac1dc 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalButton.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalButton.java @@ -14,7 +14,6 @@ import android.view.MotionEvent; import java.util.ArrayList; import java.util.List; -import java.util.TimerTask; /** * This is a digital button on screen element. It is used to get click and double click user input. @@ -42,21 +41,16 @@ public class DigitalButton extends VirtualControllerElement { void onRelease(); } - /** - * - */ - private class TimerLongClickTimerTask extends TimerTask { - @Override - public void run() { - onLongClickCallback(); - } - } - private List listeners = new ArrayList<>(); private String text = ""; private int icon = -1; private long timerLongClickTimeout = 3000; - private TimerLongClickTimerTask longClickTimerTask = null; + private final Runnable longClickRunnable = new Runnable() { + @Override + public void run() { + onLongClickCallback(); + } + }; private final Paint paint = new Paint(); private final RectF rect = new RectF(); @@ -175,13 +169,8 @@ public class DigitalButton extends VirtualControllerElement { listener.onClick(); } - if (longClickTimerTask != null) { - longClickTimerTask.cancel(); - longClickTimerTask = null; - } - - longClickTimerTask = new TimerLongClickTimerTask(); - virtualController.getTimer().schedule(longClickTimerTask, timerLongClickTimeout); + virtualController.getHandler().removeCallbacks(longClickRunnable); + virtualController.getHandler().postDelayed(longClickRunnable, timerLongClickTimeout); } private void onLongClickCallback() { @@ -200,10 +189,7 @@ public class DigitalButton extends VirtualControllerElement { } // We may be called for a release without a prior click - if (longClickTimerTask != null) { - longClickTimerTask.cancel(); - longClickTimerTask = null; - } + virtualController.getHandler().removeCallbacks(longClickRunnable); } @Override diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java index c895ca03..f20fc912 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualController.java @@ -5,6 +5,8 @@ package com.limelight.binding.input.virtual_controller; import android.content.Context; +import android.os.Handler; +import android.os.Looper; import android.util.DisplayMetrics; import android.view.View; import android.widget.Button; @@ -42,6 +44,7 @@ public class VirtualController { private final ControllerHandler controllerHandler; private final Context context; private final Timer timer; + private final Handler handler; private TimerTask retransmitTimerTask; private FrameLayout frame_layout = null; @@ -58,6 +61,7 @@ public class VirtualController { this.frame_layout = layout; this.context = context; this.timer = new Timer("OSC timer", true); + this.handler = new Handler(Looper.getMainLooper()); buttonConfigure = new Button(context); buttonConfigure.setAlpha(0.25f); @@ -92,8 +96,8 @@ public class VirtualController { } - Timer getTimer() { - return timer; + Handler getHandler() { + return handler; } public void hide() {