From d83526ff5c84a4d3fd8b6abdd842f663207d70c6 Mon Sep 17 00:00:00 2001 From: Karim Mreisi Date: Mon, 26 Jan 2015 09:38:52 +0100 Subject: [PATCH] add analog stick double click event, add button long press event, add virtual controller settings draft --- app/app.iml | 58 ++++--- app/src/main/AndroidManifest.xml | 6 + app/src/main/java/com/limelight/Game.java | 2 +- .../input/virtual_controller/AnalogStick.java | 126 ++++++++++++--- .../virtual_controller/DigitalButton.java | 67 +++++++- .../virtual_controller/VirtualController.java | 122 +++++++++++++-- .../VirtualControllerConfiguration.java | 2 +- .../VirtualControllerSettings.java | 47 ++++++ .../activity_virtual_controller_settings.xml | 143 ++++++++++++++++++ 9 files changed, 509 insertions(+), 64 deletions(-) create mode 100644 app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerSettings.java create mode 100644 app/src/main/res/layout/activity_virtual_controller_settings.xml diff --git a/app/app.iml b/app/app.iml index 4a3b7889..f7cfabed 100644 --- a/app/app.iml +++ b/app/app.iml @@ -8,10 +8,12 @@ - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -51,13 +59,13 @@ - - - - - - - + + + + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f0221cf3..1dcb1ae1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,6 +76,12 @@ android:theme="@style/StreamTheme" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" > + + diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 661d60d6..baabc55e 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -205,7 +205,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, { FrameLayout frameLayout = (FrameLayout) findViewById(R.id.frameLayout); - virtualController = new VirtualController(conn, frameLayout, getApplicationContext(), getWindowManager()); + virtualController = new VirtualController(conn, frameLayout, getApplicationContext()); } // The connection will be started when the surface gets created diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java index 19abe5a0..024c4fe5 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/AnalogStick.java @@ -8,6 +8,7 @@ import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; +import java.util.Date; import java.util.List; /** @@ -21,11 +22,20 @@ public class AnalogStick extends View MOVED } + private enum _CLICK_STATE + { + SINGLE, + DOUBLE + } + private static final boolean _PRINT_DEBUG_INFORMATION = false; public interface AnalogStickListener { void onMovement(float x, float y); + void onClick(); + void onRevoke(); + void onDoubleClick(); } public void addAnalogStickListener (AnalogStickListener listener) @@ -46,8 +56,11 @@ public class AnalogStick extends View } } - private int normalColor = 0xF0888888; - private int pressedColor = 0xF00000FF; + private int normalColor = 0xF0888888; + private int pressedColor = 0xF00000FF; + + private long timeoutDoubleClick = 250; + private long timeLastClick = 0; float radius_complete = 0; float radius_dead_zone = 0; @@ -56,8 +69,10 @@ public class AnalogStick extends View float position_stick_x = 0; float position_stick_y = 0; - boolean pressed = false; + boolean viewPressed = false; + boolean analogStickActive = false; _STICK_STATE stick_state = _STICK_STATE.NO_MOVEMENT; + _CLICK_STATE click_state = _CLICK_STATE.SINGLE; List listeners = new ArrayList(); OnTouchListener onTouchListener = null; @@ -69,8 +84,10 @@ public class AnalogStick extends View position_stick_x = getWidth() / 2; position_stick_y = getHeight() / 2; - stick_state = _STICK_STATE.NO_MOVEMENT; - pressed = false; + stick_state = _STICK_STATE.NO_MOVEMENT; + click_state = _CLICK_STATE.SINGLE; + viewPressed = false; + analogStickActive = false; } @@ -125,16 +142,25 @@ public class AnalogStick extends View paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(getPercent(getCorrectWidth() / 2, 2)); - paint.setColor(normalColor); + // draw outer circle + if (!viewPressed || click_state == _CLICK_STATE.SINGLE) + { + paint.setColor(normalColor); + } + else + { + paint.setColor(pressedColor); + } - // draw outer circle - canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint); + canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint); + + paint.setColor(normalColor); // draw dead zone canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint); // draw stick depending on state (no movement, moved, active(out of dead zone)) - if (pressed) + if (analogStickActive) { switch (stick_state) { @@ -232,7 +258,41 @@ public class AnalogStick extends View } } - private void updatePosition(float x, float y) + private void clickActionCallback() + { + _DBG("click"); + + // notify listeners + for (AnalogStickListener listener : listeners) + { + listener.onClick(); + } + } + + private void doubleClickActionCallback() + { + _DBG("double click"); + + // notify listeners + for (AnalogStickListener listener : listeners) + { + listener.onDoubleClick(); + } + } + + private void revokeActionCallback() + { + _DBG("revoke"); + + // notify listeners + for (AnalogStickListener listener : listeners) + { + listener.onRevoke(); + } + } + + + private void updatePosition(float x, float y) { float way_x = -(getWidth() / 2 - x); float way_y = -(getHeight() / 2 - y); @@ -282,33 +342,65 @@ public class AnalogStick extends View } // get masked (not specific to a pointer) action - int action = event.getActionMasked(); + int action = event.getActionMasked(); + _CLICK_STATE lastClickState = click_state; + boolean wasPressed = analogStickActive; switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: + { + viewPressed = true; + // check for double click + if (lastClickState == _CLICK_STATE.SINGLE && timeLastClick + timeoutDoubleClick > System.currentTimeMillis()) + { + click_state = _CLICK_STATE.DOUBLE; + + doubleClickActionCallback(); + } + else + { + click_state = _CLICK_STATE.SINGLE; + + clickActionCallback(); + } + + timeLastClick = System.currentTimeMillis(); + + break; + } case MotionEvent.ACTION_MOVE: - { - pressed = true; + { + if (analogStickActive || timeLastClick + timeoutDoubleClick < System.currentTimeMillis()) + { + analogStickActive = true; + } break; } - default: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: { - pressed = false; + analogStickActive = false; + viewPressed = false; + + revokeActionCallback(); break; } } - if (pressed) + if (analogStickActive) { // when is pressed calculate new positions (will trigger movement if necessary) updatePosition(event.getX(), event.getY()); } else { // no longer pressed reset movement - moveActionCallback(0, 0); + if (wasPressed) + { + moveActionCallback(0, 0); + } } // to get view refreshed 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 fdd58995..05c8f86b 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 @@ -4,28 +4,44 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.drawable.Drawable; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; /** * Created by Karim on 24.01.2015. */ public class DigitalButton extends View { + private class TimerLongClickTimerTask extends TimerTask + { + @Override + public void run() + { + onLongClickCallback(); + } + } private static final boolean _PRINT_DEBUG_INFORMATION = false; - private int normalColor = 0xF0888888; - private int pressedColor = 0xF00000FF; - private String text; + private int normalColor = 0xF0888888; + private int pressedColor = 0xF00000FF; + private String text = ""; + private int icon = -1; + + private long timerLongClickTimeout = 3000; + private Timer timerLongClick = null; + private TimerLongClickTimerTask longClickTimerTask = null; public interface DigitalButtonListener { void onClick(); - + void onLongClick(); void onRelease(); } @@ -72,6 +88,13 @@ public class DigitalButton extends View invalidate(); } + public void setIcon(int id) + { + this.icon = id; + + invalidate(); + } + private float getPercent(float value, float percent) { return value / 100 * percent; @@ -102,10 +125,19 @@ public class DigitalButton extends View paint ); - paint.setStyle(Paint.Style.FILL_AND_STROKE); - canvas.drawText(text, - getPercent(getWidth(), 50), getPercent(getHeight(), 73), - paint); + if (icon != -1) + { + Drawable d = getResources().getDrawable(icon); + d.setBounds(5, 5, getWidth() - 5, getHeight() - 5); + d.draw(canvas); + } + else + { + paint.setStyle(Paint.Style.FILL_AND_STROKE); + canvas.drawText(text, + getPercent(getWidth(), 50), getPercent(getHeight(), 73), + paint); + } super.onDraw(canvas); } @@ -119,6 +151,22 @@ public class DigitalButton extends View { listener.onClick(); } + + timerLongClick = new Timer(); + longClickTimerTask = new TimerLongClickTimerTask(); + + timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout); + } + + private void onLongClickCallback() + { + _DBG("long click"); + + // notify listeners + for (DigitalButtonListener listener : listeners) + { + listener.onLongClick(); + } } private void onReleaseCallback() @@ -130,6 +178,9 @@ public class DigitalButton extends View { listener.onRelease(); } + + timerLongClick.cancel(); + longClickTimerTask.cancel(); } 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 e6fd571d..8942c0ea 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 @@ -1,11 +1,16 @@ package com.limelight.binding.input.virtual_controller; import android.content.Context; +import android.content.Intent; +import android.view.MenuInflater; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; +import android.widget.PopupMenu; import android.widget.RelativeLayout; +import android.widget.Toast; +import com.limelight.R; import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.input.ControllerPacket; @@ -37,7 +42,6 @@ public class VirtualController private RelativeLayout.LayoutParams layoutParamsButtonStart = null; private RelativeLayout.LayoutParams layoutParamsButtonSelect = null; -// private RelativeLayout.LayoutParams layoutParamsButtonEscape = null; private RelativeLayout.LayoutParams layoutParamsDPad = null; @@ -50,12 +54,13 @@ public class VirtualController private RelativeLayout.LayoutParams layoutParamsButtonLB = null; private RelativeLayout.LayoutParams layoutParamsButtonRB = null; - private RelativeLayout.LayoutParams layoutParamsParamsStick = null; - private RelativeLayout.LayoutParams layoutParamsParamsStick2 = null; + private RelativeLayout.LayoutParams layoutParamsStick = null; + private RelativeLayout.LayoutParams layoutParamsStick2 = null; + + private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null; private DigitalButton buttonStart = null; private DigitalButton buttonSelect = null; -// private DigitalButton buttonEscape = null; private DigitalPad digitalPad = null; @@ -71,6 +76,8 @@ public class VirtualController private AnalogStick stick = null; private AnalogStick stick2 = null; + private DigitalButton buttonConfigure = null; + NvConnection connection = null; private int getPercentageV(int percent) @@ -99,8 +106,8 @@ public class VirtualController layoutParamsDPad = new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30)); - layoutParamsParamsStick = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40)); - layoutParamsParamsStick2 = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40)); + layoutParamsStick = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40)); + layoutParamsStick2 = new RelativeLayout.LayoutParams(getPercentageV(40), getPercentageV(40)); layoutParamsButtonA = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10)); layoutParamsButtonB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10)); @@ -115,10 +122,12 @@ public class VirtualController layoutParamsButtonStart = new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8)); layoutParamsButtonSelect = new RelativeLayout.LayoutParams(getPercentageH(12), getPercentageV(8)); + layoutParamsButtonConfigure = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10)); + setPercentilePosition(layoutParamsDPad, 10, 35); - setPercentilePosition(layoutParamsParamsStick, 22, 78); - setPercentilePosition(layoutParamsParamsStick2, 78, 78); + setPercentilePosition(layoutParamsStick, 22, 78); + setPercentilePosition(layoutParamsStick2, 78, 78); setPercentilePosition(layoutParamsButtonA, 85, 52); setPercentilePosition(layoutParamsButtonB, 92, 47); @@ -134,11 +143,12 @@ public class VirtualController setPercentilePosition(layoutParamsButtonSelect, 43, 94); setPercentilePosition(layoutParamsButtonStart, 57, 94); + setPercentilePosition(layoutParamsButtonConfigure, 93, 7); relative_layout.addView(digitalPad, layoutParamsDPad); - relative_layout.addView(stick, layoutParamsParamsStick); - relative_layout.addView(stick2, layoutParamsParamsStick2); + relative_layout.addView(stick, layoutParamsStick); + relative_layout.addView(stick2, layoutParamsStick2); relative_layout.addView(buttonA, layoutParamsButtonA); relative_layout.addView(buttonB, layoutParamsButtonB); @@ -151,6 +161,8 @@ public class VirtualController relative_layout.addView(buttonSelect, layoutParamsButtonSelect); relative_layout.addView(buttonStart, layoutParamsButtonStart); + + relative_layout.addView(buttonConfigure, layoutParamsButtonConfigure); } private DigitalButton createDigitalButton(String text, final int key, Context context) @@ -164,6 +176,12 @@ public class VirtualController sendControllerInputPacket(); } + @Override + public void onLongClick() + { + + } + @Override public void onRelease() { inputMap &= ~key; @@ -174,7 +192,7 @@ public class VirtualController return button; } - public VirtualController(final NvConnection conn, FrameLayout layout, Context context, WindowManager window_manager) + public VirtualController(final NvConnection conn, FrameLayout layout, final Context context) { this.connection = conn; frame_layout = layout; @@ -253,6 +271,12 @@ public class VirtualController sendControllerInputPacket(); } + @Override + public void onLongClick() + { + + } + @Override public void onRelease() { @@ -274,6 +298,12 @@ public class VirtualController sendControllerInputPacket(); } + @Override + public void onLongClick() + { + + } + @Override public void onRelease() { @@ -299,6 +329,27 @@ public class VirtualController _DBG("LEFT STICK MOVEMENT X: "+ leftStickX + " Y: " + leftStickY); sendControllerInputPacket(); } + + @Override + public void onClick() + { + } + + @Override + public void onDoubleClick() + { + inputMap |= ControllerPacket.LS_CLK_FLAG; + + sendControllerInputPacket(); + } + + @Override + public void onRevoke() + { + inputMap &= ~ControllerPacket.LS_CLK_FLAG; + + sendControllerInputPacket(); + } }); stick2 = new AnalogStick(context); @@ -313,11 +364,58 @@ public class VirtualController _DBG("RIGHT STICK MOVEMENT X: "+ rightStickX + " Y: " + rightStickY); sendControllerInputPacket(); } - }); + + @Override + public void onClick() + { + } + + @Override + public void onDoubleClick() + { + inputMap |= ControllerPacket.RS_CLK_FLAG; + + sendControllerInputPacket(); + } + + @Override + public void onRevoke() + { + inputMap &= ~ControllerPacket.RS_CLK_FLAG; + + sendControllerInputPacket(); + } + }); buttonStart = createDigitalButton("START", ControllerPacket.PLAY_FLAG, context); buttonSelect = createDigitalButton("SELECT", ControllerPacket.SPECIAL_BUTTON_FLAG, context); + buttonConfigure = new DigitalButton(context); + buttonConfigure.setIcon(R.drawable.settings); + buttonConfigure.addDigitalButtonListener(new DigitalButton.DigitalButtonListener() + { + @Override + public void onClick() { + + } + + @Override + public void onLongClick() + { + Intent virtualControllerConfiguration = new Intent(context,VirtualControllerSettings.class); + + virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + context.startActivity(virtualControllerConfiguration); + + } + + @Override + public void onRelease() { + + } + }); + refreshLayout(); } diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerConfiguration.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerConfiguration.java index a1b41938..6d8ecbd9 100644 --- a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerConfiguration.java +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerConfiguration.java @@ -37,7 +37,7 @@ public class VirtualControllerConfiguration extends Activity FrameLayout frameLayout = (FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout); // start with configuration constructor - virtualController = new VirtualController(null, frameLayout, this, getWindowManager()); + virtualController = new VirtualController(null, frameLayout, this); Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show(); } diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerSettings.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerSettings.java new file mode 100644 index 00000000..3432b63e --- /dev/null +++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerSettings.java @@ -0,0 +1,47 @@ +package com.limelight.binding.input.virtual_controller; + +import android.app.Activity; +import android.os.Bundle; +import android.view.MenuInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.PopupMenu; +import android.widget.Toast; + +import com.limelight.R; + +import org.apache.http.util.VersionInfo; + +/** + * Created by Karim on 26.01.2015. + */ +public class VirtualControllerSettings extends Activity +{ + private static VirtualController controller = null; + private static View view = null; + + static void setController(VirtualController value) + { + controller = value; + } + + static void setView(View value) + { + view = value; + } + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + // We don't want a title bar + requestWindowFeature(Window.FEATURE_NO_TITLE); + + // Inflate the content + setContentView(R.layout.activity_virtual_controller_settings); + + Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/res/layout/activity_virtual_controller_settings.xml b/app/src/main/res/layout/activity_virtual_controller_settings.xml new file mode 100644 index 00000000..f864ca91 --- /dev/null +++ b/app/src/main/res/layout/activity_virtual_controller_settings.xml @@ -0,0 +1,143 @@ + + + + + + + + +