diff --git a/app/build.gradle b/app/build.gradle
index 64fa99c1..2ac98b95 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
minSdkVersion 16
targetSdkVersion 21
- versionName "3.0.3"
- versionCode = 49
+ versionName "3.1-beta1"
+ versionCode = 50
}
productFlavors {
diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar
index db5404c7..c248abce 100644
Binary files a/app/libs/limelight-common.jar and b/app/libs/limelight-common.jar differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1dcb1ae1..a1aaa94b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -68,7 +68,7 @@
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
+ android:value="com.limelight.AppView" />
arg0, View arg1, int pos,
- long id) {
- AppObject app = (AppObject) appGridAdapter.getItem(pos);
- if (app == null || app.app == null) {
- return;
- }
- // Only open the context menu if something is running, otherwise start it
- if (getRunningAppId() != -1) {
- openContextMenu(arg1);
- } else {
- doStart(app.app);
- }
- }
- });
- registerForContextMenu(appGrid);
+ getFragmentManager().beginTransaction()
+ .add(R.id.appFragmentContainer, new AdapterFragment()).commitAllowingStateLoss();
}
@Override
@@ -283,8 +283,37 @@ public class AppView extends Activity {
}
}).start();
}
-
- public class AppObject {
+
+ @Override
+ public int getAdapterFragmentLayoutId() {
+ return PreferenceConfiguration.readPreferences(this).listMode ?
+ R.layout.list_view : R.layout.app_grid_view;
+ }
+
+ @Override
+ public void receiveAbsListView(AbsListView listView) {
+ listView.setAdapter(appGridAdapter);
+ listView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View arg1, int pos,
+ long id) {
+ AppObject app = (AppObject) appGridAdapter.getItem(pos);
+ if (app == null || app.app == null) {
+ return;
+ }
+
+ // Only open the context menu if something is running, otherwise start it
+ if (getRunningAppId() != -1) {
+ openContextMenu(arg1);
+ } else {
+ doStart(app.app);
+ }
+ }
+ });
+ registerForContextMenu(listView);
+ }
+
+ public class AppObject {
public NvApp app;
public AppObject(NvApp app) {
diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java
index baabc55e..90c58042 100644
--- a/app/src/main/java/com/limelight/Game.java
+++ b/app/src/main/java/com/limelight/Game.java
@@ -17,18 +17,23 @@ import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.input.KeyboardPacket;
import com.limelight.nvstream.input.MouseButtonPacket;
import com.limelight.preferences.PreferenceConfiguration;
+import com.limelight.ui.GameGestures;
import com.limelight.utils.Dialog;
import com.limelight.utils.SpinnerDialog;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.graphics.Point;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -43,12 +48,15 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
+import java.util.Locale;
+
public class Game extends Activity implements SurfaceHolder.Callback,
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener,
- OnSystemUiVisibilityChangeListener
+ OnSystemUiVisibilityChangeListener, GameGestures
{
private int lastMouseX = Integer.MIN_VALUE;
private int lastMouseY = Integer.MIN_VALUE;
@@ -56,6 +64,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Only 2 touches are supported
private TouchContext[] touchContextMap = new TouchContext[2];
+ private long threeFingerDownTime = 0;
+
+ private static final int THREE_FINGER_TAP_THRESHOLD = 300;
private ControllerHandler controllerHandler;
private VirtualController virtualController;
@@ -89,6 +100,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ String locale = PreferenceConfiguration.readPreferences(this).language;
+ if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
+ Configuration config = new Configuration(getResources().getConfiguration());
+ config.locale = new Locale(locale);
+ getResources().updateConfiguration(config, getResources().getDisplayMetrics());
+ }
// We don't want a title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -180,7 +198,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Initialize the connection
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
keybTranslator = new KeyboardTranslator(conn);
- controllerHandler = new ControllerHandler(conn, prefConfig.deadzonePercentage);
+ controllerHandler = new ControllerHandler(conn, this, prefConfig.deadzonePercentage);
SurfaceHolder sh = sv.getHolder();
if (prefConfig.stretchVideo || !decoderRenderer.isHardwareAccelerated()) {
@@ -478,6 +496,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
}
+ @Override
+ public void showKeyboard() {
+ LimeLog.info("Showing keyboard overlay");
+ InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
+ }
+
// Returns true if the event was consumed
private boolean handleMotionEvent(MotionEvent event) {
// Pass through keyboard input if we're not grabbing
@@ -499,7 +524,22 @@ public class Game extends Activity implements SurfaceHolder.Callback,
int actionIndex = event.getActionIndex();
int eventX = (int)event.getX(actionIndex);
- int eventY = (int)event.getY(actionIndex);
+ int eventY = (int)event.getY(actionIndex);
+
+ // Special handling for 3 finger gesture
+ if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN &&
+ event.getPointerCount() == 3) {
+ // Three fingers down
+ threeFingerDownTime = SystemClock.uptimeMillis();
+
+ // Cancel the first and second touches to avoid
+ // erroneous events
+ for (TouchContext aTouchContext : touchContextMap) {
+ aTouchContext.cancelTouch();
+ }
+
+ return true;
+ }
TouchContext context = getTouchContext(actionIndex);
if (context == null) {
@@ -514,8 +554,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
+ if (event.getPointerCount() == 1) {
+ // All fingers up
+ if (SystemClock.uptimeMillis() - threeFingerDownTime < THREE_FINGER_TAP_THRESHOLD) {
+ // This is a 3 finger tap to bring up the keyboard
+ showKeyboard();
+ return true;
+ }
+ }
context.touchUpEvent(eventX, eventY);
- if (actionIndex == 0 && event.getPointerCount() > 1) {
+ if (actionIndex == 0 && event.getPointerCount() > 1 && !context.isCancelled()) {
// The original secondary touch now becomes primary
context.touchDownEvent((int)event.getX(1), (int)event.getY(1));
}
diff --git a/app/src/main/java/com/limelight/PcView.java b/app/src/main/java/com/limelight/PcView.java
index b3b01a02..8f60d8e6 100644
--- a/app/src/main/java/com/limelight/PcView.java
+++ b/app/src/main/java/com/limelight/PcView.java
@@ -4,6 +4,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Locale;
import com.limelight.binding.PlatformBinding;
import com.limelight.binding.crypto.AndroidCryptoProvider;
@@ -16,15 +17,20 @@ import com.limelight.nvstream.http.PairingManager;
import com.limelight.nvstream.http.PairingManager.PairState;
import com.limelight.nvstream.wol.WakeOnLanSender;
import com.limelight.preferences.AddComputerManually;
+import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.preferences.StreamSettings;
+import com.limelight.ui.AdapterFragment;
+import com.limelight.ui.AdapterFragmentCallbacks;
import com.limelight.utils.Dialog;
import com.limelight.utils.UiHelper;
import android.app.Activity;
+import android.app.FragmentTransaction;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -35,15 +41,18 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.ImageButton;
+import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
-public class PcView extends Activity {
+public class PcView extends Activity implements AdapterFragmentCallbacks {
+ private AdapterFragment adapterFragment;
private RelativeLayout noPcFoundLayout;
private PcGridAdapter pcGridAdapter;
private ComputerManagerService.ComputerManagerBinder managerBinder;
@@ -102,27 +111,6 @@ public class PcView extends Activity {
ImageButton settingsButton = (ImageButton) findViewById(R.id.settingsButton);
ImageButton addComputerButton = (ImageButton) findViewById(R.id.manuallyAddPc);
- GridView pcGrid = (GridView) findViewById(R.id.pcGridView);
- pcGrid.setAdapter(pcGridAdapter);
- pcGrid.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> arg0, View arg1, int pos,
- long id) {
- ComputerObject computer = (ComputerObject) pcGridAdapter.getItem(pos);
- if (computer.details.reachability == ComputerDetails.Reachability.UNKNOWN) {
- // Do nothing
- } else if (computer.details.reachability == ComputerDetails.Reachability.OFFLINE) {
- // Open the context menu if a PC is offline
- openContextMenu(arg1);
- } else if (computer.details.pairState != PairState.PAIRED) {
- // Pair an unpaired machine by default
- doPair(computer.details);
- } else {
- doAppList(computer.details);
- }
- }
- });
- registerForContextMenu(pcGrid);
settingsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -137,6 +125,15 @@ public class PcView extends Activity {
}
});
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ if (adapterFragment != null) {
+ // Remove the old fragment
+ transaction.remove(adapterFragment);
+ }
+ adapterFragment = new AdapterFragment();
+ transaction.add(R.id.pcFragmentContainer, adapterFragment);
+ transaction.commitAllowingStateLoss();
+
noPcFoundLayout = (RelativeLayout) findViewById(R.id.no_pc_found_layout);
if (pcGridAdapter.getCount() == 0) {
noPcFoundLayout.setVisibility(View.VISIBLE);
@@ -150,12 +147,20 @@ public class PcView extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ String locale = PreferenceConfiguration.readPreferences(this).language;
+ if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
+ Configuration config = new Configuration(getResources().getConfiguration());
+ config.locale = new Locale(locale);
+ getResources().updateConfiguration(config, getResources().getDisplayMetrics());
+ }
// Bind to the computer manager service
bindService(new Intent(PcView.this, ComputerManagerService.class), serviceConnection,
Service.BIND_AUTO_CREATE);
- pcGridAdapter = new PcGridAdapter(this);
+ pcGridAdapter = new PcGridAdapter(this,
+ PreferenceConfiguration.readPreferences(this).listMode);
initializeViews();
}
@@ -561,8 +566,38 @@ public class PcView extends Activity {
// Notify the view that the data has changed
pcGridAdapter.notifyDataSetChanged();
}
-
- public class ComputerObject {
+
+ @Override
+ public int getAdapterFragmentLayoutId() {
+ return PreferenceConfiguration.readPreferences(this).listMode ?
+ R.layout.list_view : R.layout.pc_grid_view;
+ }
+
+ @Override
+ public void receiveAbsListView(AbsListView listView) {
+ listView.setAdapter(pcGridAdapter);
+ listView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View arg1, int pos,
+ long id) {
+ ComputerObject computer = (ComputerObject) pcGridAdapter.getItem(pos);
+ if (computer.details.reachability == ComputerDetails.Reachability.UNKNOWN) {
+ // Do nothing
+ } else if (computer.details.reachability == ComputerDetails.Reachability.OFFLINE) {
+ // Open the context menu if a PC is offline
+ openContextMenu(arg1);
+ } else if (computer.details.pairState != PairState.PAIRED) {
+ // Pair an unpaired machine by default
+ doPair(computer.details);
+ } else {
+ doAppList(computer.details);
+ }
+ }
+ });
+ registerForContextMenu(listView);
+ }
+
+ public class ComputerObject {
public ComputerDetails details;
public ComputerObject(ComputerDetails details) {
diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
index 3b7fb54d..df9f13a3 100644
--- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
+++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
@@ -10,6 +10,7 @@ import android.view.MotionEvent;
import com.limelight.LimeLog;
import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.ControllerPacket;
+import com.limelight.ui.GameGestures;
import com.limelight.utils.Vector2d;
public class ControllerHandler {
@@ -30,6 +31,9 @@ public class ControllerHandler {
private long lastLbUpTime = 0;
private long lastRbUpTime = 0;
private static final int MAXIMUM_BUMPER_UP_DELAY_MS = 100;
+
+ private long startDownTime = 0;
+ private static final int START_DOWN_TIME_KEYB_MS = 750;
private static final int MINIMUM_BUTTON_DOWN_TIME_MS = 25;
@@ -46,10 +50,12 @@ public class ControllerHandler {
private NvConnection conn;
private double stickDeadzone;
private final ControllerMapping defaultMapping = new ControllerMapping();
+ private GameGestures gestures;
private boolean hasGameController;
- public ControllerHandler(NvConnection conn, int deadzonePercentage) {
+ public ControllerHandler(NvConnection conn, GameGestures gestures, int deadzonePercentage) {
this.conn = conn;
+ this.gestures = gestures;
// HACK: For now we're hardcoding a 10% deadzone. Some deadzone
// is required for controller batching support to work.
@@ -513,6 +519,9 @@ public class ControllerHandler {
break;
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
+ if (SystemClock.uptimeMillis() - startDownTime > ControllerHandler.START_DOWN_TIME_KEYB_MS) {
+ gestures.showKeyboard();
+ }
inputMap &= ~ControllerPacket.PLAY_FLAG;
break;
case KeyEvent.KEYCODE_BACK:
@@ -621,6 +630,9 @@ public class ControllerHandler {
break;
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
+ if (event.getRepeatCount() == 0) {
+ startDownTime = SystemClock.uptimeMillis();
+ }
inputMap |= ControllerPacket.PLAY_FLAG;
break;
case KeyEvent.KEYCODE_BACK:
diff --git a/app/src/main/java/com/limelight/binding/input/TouchContext.java b/app/src/main/java/com/limelight/binding/input/TouchContext.java
index 91996c4b..87a38249 100644
--- a/app/src/main/java/com/limelight/binding/input/TouchContext.java
+++ b/app/src/main/java/com/limelight/binding/input/TouchContext.java
@@ -9,6 +9,7 @@ public class TouchContext {
private int originalTouchX = 0;
private int originalTouchY = 0;
private long originalTouchTime = 0;
+ private boolean cancelled;
private NvConnection conn;
private int actionIndex;
@@ -56,12 +57,17 @@ public class TouchContext {
originalTouchX = lastTouchX = eventX;
originalTouchY = lastTouchY = eventY;
originalTouchTime = System.currentTimeMillis();
-
- return true;
+ cancelled = false;
+
+ return true;
}
public void touchUpEvent(int eventX, int eventY)
{
+ if (cancelled) {
+ return;
+ }
+
if (isTap())
{
byte buttonIndex = getMouseButtonIndex();
@@ -81,8 +87,8 @@ public class TouchContext {
}
public boolean touchMoveEvent(int eventX, int eventY)
- {
- if (eventX != lastTouchX || eventY != lastTouchY)
+ {
+ if (eventX != lastTouchX || eventY != lastTouchY)
{
// We only send moves for the primary touch point
if (actionIndex == 0) {
@@ -102,4 +108,12 @@ public class TouchContext {
return true;
}
+
+ public void cancelTouch() {
+ cancelled = true;
+ }
+
+ public boolean isCancelled() {
+ return cancelled;
+ }
}
diff --git a/app/src/main/java/com/limelight/binding/input/evdev/EvdevReader.java b/app/src/main/java/com/limelight/binding/input/evdev/EvdevReader.java
index d5c7c6de..ddb3a7ba 100644
--- a/app/src/main/java/com/limelight/binding/input/evdev/EvdevReader.java
+++ b/app/src/main/java/com/limelight/binding/input/evdev/EvdevReader.java
@@ -26,7 +26,7 @@ public class EvdevReader {
// 4.4 and later to do live SELinux policy changes.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
EvdevShell shell = EvdevShell.getInstance();
- shell.runCommand("supolicy --live \"allow untrusted_app input_device dir getattr\" " +
+ shell.runCommand("supolicy --live \"allow untrusted_app input_device dir { getattr read search }\" " +
"\"allow untrusted_app input_device chr_file { open read write ioctl }\"");
}
}
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 024c4fe5..131d9acb 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
@@ -5,106 +5,56 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
-import android.view.View;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
/**
* Created by Karim Mreisi on 30.11.2014.
*/
-public class AnalogStick extends View
+public class AnalogStick extends VirtualControllerElement
{
- private enum _STICK_STATE
- {
- NO_MOVEMENT,
- MOVED
- }
+ protected static boolean _PRINT_DEBUG_INFORMATION = true;
- private enum _CLICK_STATE
- {
- SINGLE,
- DOUBLE
- }
+ float radius_complete = 0;
+ float radius_dead_zone = 0;
+ float radius_analog_stick = 0;
+ float position_stick_x = 0;
+ float position_stick_y = 0;
- private static final boolean _PRINT_DEBUG_INFORMATION = false;
+ boolean viewPressed = false;
+ boolean analogStickActive = false;
- public interface AnalogStickListener
- {
- void onMovement(float x, float y);
- void onClick();
- void onRevoke();
- void onDoubleClick();
- }
+ _STICK_STATE stick_state = _STICK_STATE.NO_MOVEMENT;
+ _CLICK_STATE click_state = _CLICK_STATE.SINGLE;
- public void addAnalogStickListener (AnalogStickListener listener)
- {
- listeners.add(listener);
- }
-
- public void setOnTouchListener(OnTouchListener listener)
- {
- onTouchListener = listener;
- }
-
- private static final void _DBG(String text)
- {
- if (_PRINT_DEBUG_INFORMATION)
- {
- System.out.println("AnalogStick: " + text);
- }
- }
-
- 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;
- float radius_analog_stick = 0;
-
- float position_stick_x = 0;
- float position_stick_y = 0;
-
- 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;
+ List listeners = new ArrayList();
+ OnTouchListener onTouchListener = null;
+ private long timeoutDoubleClick = 250;
+ private long timeLastClick = 0;
public AnalogStick(Context context)
{
super(context);
- position_stick_x = getWidth() / 2;
- position_stick_y = getHeight() / 2;
-
- stick_state = _STICK_STATE.NO_MOVEMENT;
- click_state = _CLICK_STATE.SINGLE;
- viewPressed = false;
- analogStickActive = false;
-
+ position_stick_x = getWidth() / 2;
+ position_stick_y = getHeight() / 2;
}
- public void setColors(int normalColor, int pressedColor)
- {
- this.normalColor = normalColor;
- this.pressedColor = pressedColor;
- }
-
- private float getPercent(float value, int percent)
+ public void addAnalogStickListener(AnalogStickListener listener)
{
- return value / 100 * percent;
+ listeners.add(listener);
}
- private int getCorrectWidth()
+ public void setOnTouchListener(OnTouchListener listener)
{
- return getWidth() > getHeight() ? getHeight() : getWidth();
+ onTouchListener = listener;
+ }
+
+ public void setColors(int normalColor, int pressedColor)
+ {
+ this.normalColor = normalColor;
+ this.pressedColor = pressedColor;
}
private double getMovementRadius(float x, float y)
@@ -119,15 +69,15 @@ public class AnalogStick extends View
return x > 0 ? x : -x;
}
- return Math.sqrt(x * x + y * y);
+ return Math.sqrt(x * x + y * y);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
- radius_complete = getPercent(getCorrectWidth() / 2, 95);
- radius_dead_zone = getPercent(getCorrectWidth() / 2, 20);
- radius_analog_stick = getPercent(getCorrectWidth() / 2, 30);
+ radius_complete = getPercent(getCorrectWidth() / 2, 95);
+ radius_dead_zone = getPercent(getCorrectWidth() / 2, 20);
+ radius_analog_stick = getPercent(getCorrectWidth() / 2, 30);
super.onSizeChanged(w, h, oldw, oldh);
}
@@ -135,29 +85,29 @@ public class AnalogStick extends View
@Override
protected void onDraw(Canvas canvas)
{
- // set transparent background
- canvas.drawColor(Color.TRANSPARENT);
+ // set transparent background
+ canvas.drawColor(Color.TRANSPARENT);
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(getPercent(getCorrectWidth() / 2, 2));
- // draw outer circle
- if (!viewPressed || click_state == _CLICK_STATE.SINGLE)
- {
- paint.setColor(normalColor);
- }
- else
- {
- paint.setColor(pressedColor);
- }
+ // draw outer circle
+ if (!viewPressed || click_state == _CLICK_STATE.SINGLE)
+ {
+ paint.setColor(normalColor);
+ }
+ else
+ {
+ paint.setColor(pressedColor);
+ }
- canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint);
+ canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_complete, paint);
- paint.setColor(normalColor);
+ paint.setColor(normalColor);
// draw dead zone
- canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint);
+ canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius_dead_zone, paint);
// draw stick depending on state (no movement, moved, active(out of dead zone))
if (analogStickActive)
@@ -209,11 +159,11 @@ public class AnalogStick extends View
{
if (way_x > 0)
{
- angle = Math.PI * 3/2;
+ angle = Math.PI * 3 / 2;
}
else if (way_x < 0)
{
- angle = Math.PI * 1/2;
+ angle = Math.PI * 1 / 2;
}
}
else
@@ -221,30 +171,31 @@ public class AnalogStick extends View
if (way_x > 0)
{
if (way_y < 0)
- { // first quadrant
- angle = 3 * Math.PI / 2 + Math.atan((double)(-way_y / way_x));
+ { // first quadrant
+ angle =
+ 3 * Math.PI / 2 + Math.atan((double) (-way_y / way_x));
}
else
- { // second quadrant
- angle = Math.PI + Math.atan((double)(way_x / way_y));
+ { // second quadrant
+ angle = Math.PI + Math.atan((double) (way_x / way_y));
}
}
else
{
if (way_y > 0)
- { // third quadrant
- angle = Math.PI / 2 + Math.atan((double)(way_y / -way_x));
+ { // third quadrant
+ angle = Math.PI / 2 + Math.atan((double) (way_y / -way_x));
}
else
- { // fourth quadrant
+ { // fourth quadrant
angle = 0 + Math.atan((double) (-way_x / -way_y));
}
}
}
- _DBG("angle: " + angle + " way y: "+ way_y + " way x: " + way_x);
+ _DBG("angle: " + angle + " way y: " + way_y + " way x: " + way_x);
- return angle;
+ return angle;
}
private void moveActionCallback(float x, float y)
@@ -258,50 +209,49 @@ public class AnalogStick extends View
}
}
- 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)
+ private void clickActionCallback()
{
- float way_x = -(getWidth() / 2 - x);
- float way_y = -(getHeight() / 2 - y);
+ _DBG("click");
- float movement_x = 0;
- float movement_y = 0;
+ // notify listeners
+ for (AnalogStickListener listener : listeners)
+ {
+ listener.onClick();
+ }
+ }
- double movement_radius = getMovementRadius(way_x, way_y);
- double movement_angle = getAngle(way_x, way_y);
+ 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);
+
+ float movement_x = 0;
+ float movement_y = 0;
+
+ double movement_radius = getMovementRadius(way_x, way_y);
+ double movement_angle = getAngle(way_x, way_y);
// chop radius if out of outer circle
if (movement_radius > (radius_complete - radius_analog_stick))
@@ -309,8 +259,10 @@ public class AnalogStick extends View
movement_radius = radius_complete - radius_analog_stick;
}
- float correlated_y = (float)(Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
- float correlated_x = (float)(Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
+ float correlated_y =
+ (float) (Math.sin(Math.PI / 2 - movement_angle) * (movement_radius));
+ float correlated_x =
+ (float) (Math.cos(Math.PI / 2 - movement_angle) * (movement_radius));
float complete = (radius_complete - radius_analog_stick);
@@ -336,71 +288,69 @@ public class AnalogStick extends View
@Override
public boolean onTouchEvent(MotionEvent event)
{
- if (onTouchListener != null)
- {
- return onTouchListener.onTouch(this, event);
- }
+ if (onTouchListener != null)
+ {
+ return onTouchListener.onTouch(this, event);
+ }
// get masked (not specific to a pointer) action
- int action = event.getActionMasked();
- _CLICK_STATE lastClickState = click_state;
- boolean wasPressed = analogStickActive;
+ 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;
+ {
+ 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;
+ doubleClickActionCallback();
+ }
+ else
+ {
+ click_state = _CLICK_STATE.SINGLE;
- clickActionCallback();
- }
+ clickActionCallback();
+ }
- timeLastClick = System.currentTimeMillis();
-
- break;
- }
- case MotionEvent.ACTION_MOVE:
- {
- if (analogStickActive || timeLastClick + timeoutDoubleClick < System.currentTimeMillis())
- {
- analogStickActive = true;
- }
+ timeLastClick = System.currentTimeMillis();
break;
}
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_MOVE:
{
- analogStickActive = false;
- viewPressed = false;
+ if (analogStickActive || timeLastClick + timeoutDoubleClick < System.currentTimeMillis())
+ {
+ analogStickActive = true;
+ }
- revokeActionCallback();
+ break;
+ }
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ {
+ analogStickActive = false;
+ viewPressed = false;
+
+ revokeActionCallback();
break;
}
}
+ // no longer pressed reset movement
if (analogStickActive)
- { // when is pressed calculate new positions (will trigger movement if necessary)
+ { // when is pressed calculate new positions (will trigger movement if necessary)
updatePosition(event.getX(), event.getY());
}
- else
- { // no longer pressed reset movement
- if (wasPressed)
- {
- moveActionCallback(0, 0);
- }
+ else if (wasPressed)
+ {
+ moveActionCallback(0, 0);
}
// to get view refreshed
@@ -408,4 +358,28 @@ public class AnalogStick extends View
return true;
}
+
+ private enum _STICK_STATE
+ {
+ NO_MOVEMENT,
+ MOVED
+ }
+
+
+ private enum _CLICK_STATE
+ {
+ SINGLE,
+ DOUBLE
+ }
+
+ public interface AnalogStickListener
+ {
+ void onMovement(float x, float y);
+
+ void onClick();
+
+ void onRevoke();
+
+ void onDoubleClick();
+ }
}
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 05c8f86b..7c012c9c 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
@@ -6,7 +6,6 @@ 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;
@@ -16,214 +15,181 @@ import java.util.TimerTask;
/**
* Created by Karim on 24.01.2015.
*/
-public class DigitalButton extends View
+public class DigitalButton extends VirtualControllerElement
{
- private class TimerLongClickTimerTask extends TimerTask
- {
- @Override
- public void run()
- {
- onLongClickCallback();
- }
- }
- private static final boolean _PRINT_DEBUG_INFORMATION = false;
+ List listeners = new ArrayList();
+ OnTouchListener onTouchListener = null;
+ boolean clicked;
+ private String text = "";
+ private int icon = -1;
+ private long timerLongClickTimeout = 3000;
+ private Timer timerLongClick = null;
+ private TimerLongClickTimerTask longClickTimerTask = null;
- private int normalColor = 0xF0888888;
- private int pressedColor = 0xF00000FF;
- private String text = "";
- private int icon = -1;
+ public DigitalButton(Context context)
+ {
+ super(context);
+ clicked = false;
+ }
- private long timerLongClickTimeout = 3000;
- private Timer timerLongClick = null;
- private TimerLongClickTimerTask longClickTimerTask = null;
+ public void addDigitalButtonListener(DigitalButtonListener listener)
+ {
+ listeners.add(listener);
+ }
+ public void setOnTouchListener(OnTouchListener listener)
+ {
+ onTouchListener = listener;
+ }
- public interface DigitalButtonListener
- {
- void onClick();
- void onLongClick();
- void onRelease();
- }
+ public void setText(String text)
+ {
+ this.text = text;
+ invalidate();
+ }
- public void addDigitalButtonListener(DigitalButtonListener listener)
- {
- listeners.add(listener);
- }
+ public void setIcon(int id)
+ {
+ this.icon = id;
+ invalidate();
+ }
- public void setColors(int normalColor, int pressedColor)
- {
- this.normalColor = normalColor;
- this.pressedColor = pressedColor;
- }
+ @Override
+ protected void onDraw(Canvas canvas)
+ {
+ // set transparent background
+ canvas.drawColor(Color.TRANSPARENT);
- public void setOnTouchListener(OnTouchListener listener)
- {
- onTouchListener = listener;
- }
+ Paint paint = new Paint();
- private static final void _DBG(String text)
- {
- if (_PRINT_DEBUG_INFORMATION)
- {
- System.out.println("DigitalButton: " + text);
- }
- }
+ paint.setTextSize(getPercent(getCorrectWidth(), 50));
+ paint.setTextAlign(Paint.Align.CENTER);
+ paint.setStrokeWidth(3);
- List listeners = new ArrayList();
- OnTouchListener onTouchListener = null;
+ paint.setColor(clicked ? pressedColor : normalColor);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(
+ 1, 1,
+ getWidth() - 1, getHeight() - 1,
+ paint
+ );
- boolean clicked;
+ 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);
+ }
- public DigitalButton(Context context)
- {
- super(context);
+ super.onDraw(canvas);
+ }
- clicked = false;
- }
+ private void onClickCallback()
+ {
+ _DBG("clicked");
- public void setText(String text)
- {
- this.text = text;
+ // notify listeners
+ for (DigitalButtonListener listener : listeners)
+ {
+ listener.onClick();
+ }
- invalidate();
- }
+ timerLongClick = new Timer();
+ longClickTimerTask = new TimerLongClickTimerTask();
- public void setIcon(int id)
- {
- this.icon = id;
+ timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
+ }
- invalidate();
- }
+ private void onLongClickCallback()
+ {
+ _DBG("long click");
- private float getPercent(float value, float percent)
- {
- return value / 100 * percent;
- }
+ // notify listeners
+ for (DigitalButtonListener listener : listeners)
+ {
+ listener.onLongClick();
+ }
+ }
- private int getCorrectWidth()
- {
- return getWidth() > getHeight() ? getHeight() : getWidth();
- }
+ private void onReleaseCallback()
+ {
+ _DBG("released");
- @Override
- protected void onDraw(Canvas canvas)
- {
- // set transparent background
- canvas.drawColor(Color.TRANSPARENT);
+ // notify listeners
+ for (DigitalButtonListener listener : listeners)
+ {
+ listener.onRelease();
+ }
- Paint paint = new Paint();
+ timerLongClick.cancel();
+ longClickTimerTask.cancel();
+ }
- paint.setTextSize(getPercent(getCorrectWidth(), 50));
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setStrokeWidth(3);
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ /*
+ if (onTouchListener != null)
+ {
+ return onTouchListener.onTouch(this, event);
+ }
+ */
+ // get masked (not specific to a pointer) action
+ int action = event.getActionMasked();
- paint.setColor(clicked ? pressedColor : normalColor);
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(
- 1, 1,
- getWidth() - 1, getHeight() - 1,
- paint
- );
+ switch (action)
+ {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ {
+ clicked = true;
+ onClickCallback();
- 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);
- }
+ invalidate();
- super.onDraw(canvas);
- }
+ return true;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ {
+ clicked = false;
+ onReleaseCallback();
- private void onClickCallback()
- {
- _DBG("clicked");
+ invalidate();
- // notify listeners
- for (DigitalButtonListener listener : listeners)
- {
- listener.onClick();
- }
+ return true;
+ }
+ default:
+ {
+ }
+ }
- timerLongClick = new Timer();
- longClickTimerTask = new TimerLongClickTimerTask();
+ return true;
+ }
- timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
- }
+ public interface DigitalButtonListener
+ {
+ void onClick();
- private void onLongClickCallback()
- {
- _DBG("long click");
+ void onLongClick();
- // notify listeners
- for (DigitalButtonListener listener : listeners)
- {
- listener.onLongClick();
- }
- }
+ void onRelease();
+ }
- private void onReleaseCallback()
- {
- _DBG("released");
-
- // notify listeners
- for (DigitalButtonListener listener : listeners)
- {
- listener.onRelease();
- }
-
- timerLongClick.cancel();
- longClickTimerTask.cancel();
- }
-
-
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- /*
- if (onTouchListener != null)
- {
- return onTouchListener.onTouch(this, event);
- }
- */
- // get masked (not specific to a pointer) action
- int action = event.getActionMasked();
-
- switch (action)
- {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- {
- clicked = true;
- onClickCallback();
-
- invalidate();
-
- return true;
- }
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- {
- clicked = false;
- onReleaseCallback();
-
- invalidate();
-
- return true;
- }
- default:
- {
- }
- }
-
- return true;
- }
+ private class TimerLongClickTimerTask extends TimerTask
+ {
+ @Override
+ public void run()
+ {
+ onLongClickCallback();
+ }
+ }
}
diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalPad.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalPad.java
index 0722fcf1..d7171d22 100644
--- a/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalPad.java
+++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/DigitalPad.java
@@ -5,7 +5,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
-import android.view.View;
import java.util.ArrayList;
import java.util.List;
@@ -13,273 +12,244 @@ import java.util.List;
/**
* Created by Karim Mreisi on 23.01.2015.
*/
-public class DigitalPad extends View
+public class DigitalPad extends VirtualControllerElement
{
- public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0;
- public final static int DIGITAL_PAD_DIRECTION_LEFT = 1;
- public final static int DIGITAL_PAD_DIRECTION_UP = 2;
- public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4;
- public final static int DIGITAL_PAD_DIRECTION_DOWN = 8;
+ public final static int DIGITAL_PAD_DIRECTION_NO_DIRECTION = 0;
+ int direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION;
+ public final static int DIGITAL_PAD_DIRECTION_LEFT = 1;
+ public final static int DIGITAL_PAD_DIRECTION_UP = 2;
+ public final static int DIGITAL_PAD_DIRECTION_RIGHT = 4;
+ public final static int DIGITAL_PAD_DIRECTION_DOWN = 8;
+ List listeners = new ArrayList();
+ OnTouchListener onTouchListener = null;
- private int normalColor = 0xF0888888;
- private int pressedColor = 0xF00000FF;
+ public DigitalPad(Context context)
+ {
+ super(context);
+ }
- private static final boolean _PRINT_DEBUG_INFORMATION = false;
+ public void addDigitalPadListener(DigitalPadListener listener)
+ {
+ listeners.add(listener);
+ }
- public interface DigitalPadListener
- {
- void onDirectionChange(int direction);
- }
+ public void setOnTouchListener(OnTouchListener listener)
+ {
+ onTouchListener = listener;
+ }
- public void addDigitalPadListener (DigitalPadListener listener)
- {
- listeners.add(listener);
- }
+ @Override
+ protected void onDraw(Canvas canvas)
+ {
+ // set transparent background
+ canvas.drawColor(Color.TRANSPARENT);
- public void setOnTouchListener(OnTouchListener listener)
- {
- onTouchListener = listener;
- }
+ Paint paint = new Paint();
- private static final void _DBG(String text)
- {
- if (_PRINT_DEBUG_INFORMATION)
- {
- System.out.println("DigitalPad: " + text);
- }
- }
+ paint.setTextSize(getPercent(getCorrectWidth(), 20));
+ paint.setTextAlign(Paint.Align.CENTER);
+ paint.setStrokeWidth(3);
- List listeners = new ArrayList();
- OnTouchListener onTouchListener = null;
+ if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION)
+ {
+ // draw no direction rect
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(normalColor);
+ canvas.drawRect(
+ getPercent(getWidth(), 36), getPercent(getHeight(), 36),
+ getPercent(getWidth(), 63), getPercent(getHeight(), 63),
+ paint
+ );
+ }
- int direction;
+ // draw left rect
+ paint.setColor(
+ (direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 ? pressedColor : normalColor);
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawText("LF",
+ getPercent(getWidth(), 16.5f), getPercent(getHeight(), 56),
+ paint);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(
+ 0, getPercent(getHeight(), 33),
+ getPercent(getWidth(), 33), getPercent(getHeight(), 66),
+ paint
+ );
- public DigitalPad(Context context)
- {
- super(context);
+ // draw left up line
+ paint.setColor((
+ (direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 &&
+ (direction & DIGITAL_PAD_DIRECTION_UP) > 0
+ ) ? pressedColor : normalColor
+ );
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawLine(
+ 0, getPercent(getWidth(), 33),
+ getPercent(getWidth(), 33), 0,
+ paint
+ );
- direction = DIGITAL_PAD_DIRECTION_NO_DIRECTION;
- }
+ // draw up rect
+ paint.setColor(
+ (direction & DIGITAL_PAD_DIRECTION_UP) > 0 ? pressedColor : normalColor);
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawText("UP",
+ getPercent(getWidth(), 49.5f), getPercent(getHeight(), 23),
+ paint);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(
+ getPercent(getWidth(), 33), 0,
+ getPercent(getWidth(), 66), getPercent(getHeight(), 33),
+ paint
+ );
- private float getPercent(float value, float percent)
- {
- return value / 100 * percent;
- }
+ // draw up right line
+ paint.setColor((
+ (direction & DIGITAL_PAD_DIRECTION_UP) > 0 &&
+ (direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0
+ ) ? pressedColor : normalColor
+ );
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawLine(
+ getPercent(getWidth(), 66), 0,
+ getPercent(getWidth(), 100), getPercent(getHeight(), 33),
+ paint
+ );
- private int getCorrectWidth()
- {
- return getWidth() > getHeight() ? getHeight() : getWidth();
- }
+ // draw right rect
+ paint.setColor(
+ (direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 ? pressedColor : normalColor);
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawText("RI",
+ getPercent(getWidth(), 82.5f), getPercent(getHeight(), 56),
+ paint);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(
+ getPercent(getWidth(), 66), getPercent(getHeight(), 33),
+ getPercent(getWidth(), 100), getPercent(getHeight(), 66),
+ paint
+ );
- public void setColors(int normalColor, int pressedColor)
- {
- this.normalColor = normalColor;
- this.pressedColor = pressedColor;
- }
+ // draw right down line
+ paint.setColor((
+ (direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 &&
+ (direction & DIGITAL_PAD_DIRECTION_DOWN) > 0
+ ) ? pressedColor : normalColor
+ );
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawLine(
+ getPercent(getWidth(), 100), getPercent(getHeight(), 66),
+ getPercent(getWidth(), 66), getPercent(getHeight(), 100),
+ paint
+ );
- @Override
- protected void onDraw(Canvas canvas)
- {
- // set transparent background
- canvas.drawColor(Color.TRANSPARENT);
+ // draw down rect
+ paint.setColor(
+ (direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 ? pressedColor : normalColor);
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawText("DW",
+ getPercent(getWidth(), 49.5f), getPercent(getHeight(), 89),
+ paint);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(
+ getPercent(getWidth(), 33), getPercent(getHeight(), 66),
+ getPercent(getWidth(), 66), getPercent(getHeight(), 100),
+ paint
+ );
- Paint paint = new Paint();
+ // draw down left line
+ paint.setColor((
+ (direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 &&
+ (direction & DIGITAL_PAD_DIRECTION_LEFT) > 0
+ ) ? pressedColor : normalColor
+ );
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawLine(
+ getPercent(getWidth(), 33), getPercent(getHeight(), 100),
+ getPercent(getWidth(), 0), getPercent(getHeight(), 66),
+ paint
+ );
- paint.setTextSize(getPercent(getCorrectWidth(), 20));
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setStrokeWidth(3);
+ super.onDraw(canvas);
+ }
- if (direction == DIGITAL_PAD_DIRECTION_NO_DIRECTION)
- {
- // draw no direction rect
- paint.setStyle(Paint.Style.STROKE);
- paint.setColor(normalColor);
- canvas.drawRect(
- getPercent(getWidth(), 36), getPercent(getHeight(), 36),
- getPercent(getWidth(), 63), getPercent(getHeight(), 63),
- paint
- );
- }
+ private void newDirectionCallback(int direction)
+ {
+ _DBG("direction: " + direction);
- // draw left rect
- paint.setColor((direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 ? pressedColor : normalColor);
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawText("LF",
- getPercent(getWidth(), 16.5f), getPercent(getHeight(), 56),
- paint);
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(
- 0, getPercent(getHeight(), 33),
- getPercent(getWidth(), 33), getPercent(getHeight(), 66),
- paint
- );
+ // notify listeners
+ for (DigitalPadListener listener : listeners)
+ {
+ listener.onDirectionChange(direction);
+ }
+ }
- // draw left up line
- paint.setColor((
- (direction & DIGITAL_PAD_DIRECTION_LEFT) > 0 &&
- (direction & DIGITAL_PAD_DIRECTION_UP) > 0
- ) ? pressedColor : normalColor
- );
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawLine(
- 0, getPercent(getWidth(), 33),
- getPercent(getWidth(), 33), 0,
- paint
- );
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ if (onTouchListener != null)
+ {
+ return onTouchListener.onTouch(this, event);
+ }
- // draw up rect
- paint.setColor((direction & DIGITAL_PAD_DIRECTION_UP) > 0 ? pressedColor : normalColor);
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawText("UP",
- getPercent(getWidth(), 49.5f), getPercent(getHeight(), 23),
- paint);
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(
- getPercent(getWidth(), 33), 0,
- getPercent(getWidth(), 66), getPercent(getHeight(), 33),
- paint
- );
+ // get masked (not specific to a pointer) action
+ int action = event.getActionMasked();
- // draw up right line
- paint.setColor((
- (direction & DIGITAL_PAD_DIRECTION_UP) > 0 &&
- (direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0
- ) ? pressedColor : normalColor
- );
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawLine(
- getPercent(getWidth(), 66), 0,
- getPercent(getWidth(), 100), getPercent(getHeight(), 33),
- paint
- );
+ switch (action)
+ {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ {
+ direction = 0;
- // draw right rect
- paint.setColor((direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 ? pressedColor : normalColor);
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawText("RI",
- getPercent(getWidth(), 82.5f), getPercent(getHeight(), 56),
- paint);
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(
- getPercent(getWidth(), 66), getPercent(getHeight(), 33),
- getPercent(getWidth(), 100), getPercent(getHeight(), 66),
- paint
- );
+ if (event.getX() < getPercent(getWidth(), 33))
+ {
+ direction |= DIGITAL_PAD_DIRECTION_LEFT;
+ }
- // draw right down line
- paint.setColor((
- (direction & DIGITAL_PAD_DIRECTION_RIGHT) > 0 &&
- (direction & DIGITAL_PAD_DIRECTION_DOWN) > 0
- ) ? pressedColor : normalColor
- );
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawLine(
- getPercent(getWidth(), 100), getPercent(getHeight(), 66),
- getPercent(getWidth(), 66), getPercent(getHeight(), 100),
- paint
- );
+ if (event.getX() > getPercent(getWidth(), 66))
+ {
+ direction |= DIGITAL_PAD_DIRECTION_RIGHT;
+ }
- // draw down rect
- paint.setColor((direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 ? pressedColor : normalColor);
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawText("DW",
- getPercent(getWidth(), 49.5f), getPercent(getHeight(), 89),
- paint);
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawRect(
- getPercent(getWidth(), 33), getPercent(getHeight(), 66),
- getPercent(getWidth(), 66), getPercent(getHeight(), 100),
- paint
- );
+ if (event.getY() > getPercent(getHeight(), 66))
+ {
+ direction |= DIGITAL_PAD_DIRECTION_DOWN;
+ }
- // draw down left line
- paint.setColor((
- (direction & DIGITAL_PAD_DIRECTION_DOWN) > 0 &&
- (direction & DIGITAL_PAD_DIRECTION_LEFT) > 0
- ) ? pressedColor : normalColor
- );
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawLine(
- getPercent(getWidth(), 33), getPercent(getHeight(), 100),
- getPercent(getWidth(), 0), getPercent(getHeight(), 66),
- paint
- );
+ if (event.getY() < getPercent(getHeight(), 33))
+ {
+ direction |= DIGITAL_PAD_DIRECTION_UP;
+ }
- super.onDraw(canvas);
- }
+ newDirectionCallback(direction);
- private void newDirectionCallback(int direction)
- {
- _DBG("direction: " + direction);
+ invalidate();
- // notify listeners
- for (DigitalPadListener listener : listeners)
- {
- listener.onDirectionChange(direction);
- }
- }
+ return true;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ {
+ direction = 0;
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- if (onTouchListener != null)
- {
- return onTouchListener.onTouch(this, event);
- }
+ newDirectionCallback(direction);
- // get masked (not specific to a pointer) action
- int action = event.getActionMasked();
+ invalidate();
- switch (action)
- {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- {
- direction = 0;
+ return true;
+ }
+ default:
+ {
+ }
+ }
- if (event.getX() < getPercent(getWidth(), 33))
- {
- direction |= DIGITAL_PAD_DIRECTION_LEFT;
- }
+ return true;
+ }
- if (event.getX() > getPercent(getWidth(), 66))
- {
- direction |= DIGITAL_PAD_DIRECTION_RIGHT;
- }
-
- if (event.getY() > getPercent(getHeight(), 66))
- {
- direction |= DIGITAL_PAD_DIRECTION_DOWN;
- }
-
- if (event.getY() < getPercent(getHeight(), 33))
- {
- direction |= DIGITAL_PAD_DIRECTION_UP;
- }
-
- newDirectionCallback(direction);
-
- invalidate();
-
- return true;
- }
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- {
- direction = 0;
-
- newDirectionCallback(direction);
-
- invalidate();
-
- return true;
- }
- default:
- {
- }
- }
-
- return true;
- }
+ public interface DigitalPadListener
+ {
+ void onDirectionChange(int direction);
+ }
}
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 8942c0ea..87c9a2a7 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
@@ -2,13 +2,9 @@ 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;
@@ -19,183 +15,63 @@ import com.limelight.nvstream.input.ControllerPacket;
*/
public class VirtualController
{
- private static final boolean _PRINT_DEBUG_INFORMATION = false;
+ private static final boolean _PRINT_DEBUG_INFORMATION = false;
+ NvConnection connection = null;
+ private Context context = null;
+ private short inputMap = 0x0000;
+ private byte leftTrigger = 0x00;
+ private byte rightTrigger = 0x00;
+ private short rightStickX = 0x0000;
+ private short rightStickY = 0x0000;
+ private short leftStickX = 0x0000;
+ private short leftStickY = 0x0000;
- private static final void _DBG(String text)
- {
- if (_PRINT_DEBUG_INFORMATION)
- {
- System.out.println("VirtualController: " + text);
- }
- }
+ private FrameLayout frame_layout = null;
+ private RelativeLayout relative_layout = null;
- private short inputMap = 0x0000;
- private byte leftTrigger = 0x00;
- private byte rightTrigger = 0x00;
- private short rightStickX = 0x0000;
- private short rightStickY = 0x0000;
- private short leftStickX = 0x0000;
- private short leftStickY = 0x0000;
+ private RelativeLayout.LayoutParams layoutParamsButtonStart = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonSelect = null;
- private FrameLayout frame_layout = null;
- private RelativeLayout relative_layout = null;
+ private RelativeLayout.LayoutParams layoutParamsDPad = null;
- private RelativeLayout.LayoutParams layoutParamsButtonStart = null;
- private RelativeLayout.LayoutParams layoutParamsButtonSelect = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonA = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonB = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonX = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonY = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonLT = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonRT = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonLB = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonRB = null;
- private RelativeLayout.LayoutParams layoutParamsDPad = null;
+ private RelativeLayout.LayoutParams layoutParamsStick = null;
+ private RelativeLayout.LayoutParams layoutParamsStick2 = null;
- private RelativeLayout.LayoutParams layoutParamsButtonA = null;
- private RelativeLayout.LayoutParams layoutParamsButtonB = null;
- private RelativeLayout.LayoutParams layoutParamsButtonX = null;
- private RelativeLayout.LayoutParams layoutParamsButtonY = null;
- private RelativeLayout.LayoutParams layoutParamsButtonLT = null;
- private RelativeLayout.LayoutParams layoutParamsButtonRT = null;
- private RelativeLayout.LayoutParams layoutParamsButtonLB = null;
- private RelativeLayout.LayoutParams layoutParamsButtonRB = null;
+ private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null;
- private RelativeLayout.LayoutParams layoutParamsStick = null;
- private RelativeLayout.LayoutParams layoutParamsStick2 = null;
+ private DigitalButton buttonStart = null;
+ private DigitalButton buttonSelect = null;
- private RelativeLayout.LayoutParams layoutParamsButtonConfigure = null;
+ private DigitalPad digitalPad = null;
- private DigitalButton buttonStart = null;
- private DigitalButton buttonSelect = null;
+ private DigitalButton buttonA = null;
+ private DigitalButton buttonB = null;
+ private DigitalButton buttonX = null;
+ private DigitalButton buttonY = null;
+ private DigitalButton buttonLT = null;
+ private DigitalButton buttonRT = null;
+ private DigitalButton buttonLB = null;
+ private DigitalButton buttonRB = null;
- private DigitalPad digitalPad = null;
+ private AnalogStick stick = null;
+ private AnalogStick stick2 = null;
- private DigitalButton buttonA = null;
- private DigitalButton buttonB = null;
- private DigitalButton buttonX = null;
- private DigitalButton buttonY = null;
- private DigitalButton buttonLT = null;
- private DigitalButton buttonRT = null;
- private DigitalButton buttonLB = null;
- private DigitalButton buttonRB = null;
-
- private AnalogStick stick = null;
- private AnalogStick stick2 = null;
-
- private DigitalButton buttonConfigure = null;
-
- NvConnection connection = null;
-
- private int getPercentageV(int percent)
- {
- return (int)(((float)frame_layout.getHeight() / (float)100) * (float)percent);
- }
-
- private int getPercentageH(int percent)
- {
- return (int)(((float)frame_layout.getWidth() / (float)100) * (float)percent);
- }
-
- private void setPercentilePosition(RelativeLayout.LayoutParams parm, float pos_x, float pos_y)
- {
- parm.setMargins(
- (int)(((float)frame_layout.getWidth() / (float)100 * pos_x) - ((float)parm.width / (float)2)),
- (int)(((float)frame_layout.getHeight() / (float)100 * pos_y) - ((float)parm.height / (float)2)),
- 0,
- 0
- );
- }
-
- void refreshLayout()
- {
- relative_layout.removeAllViews();
-
- layoutParamsDPad = new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30));
-
- 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));
- layoutParamsButtonX = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
- layoutParamsButtonY = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
- layoutParamsButtonLT = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
- layoutParamsButtonRT = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
-
- layoutParamsButtonLB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
- layoutParamsButtonRB = new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
-
- 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(layoutParamsStick, 22, 78);
- setPercentilePosition(layoutParamsStick2, 78, 78);
-
- setPercentilePosition(layoutParamsButtonA, 85, 52);
- setPercentilePosition(layoutParamsButtonB, 92, 47);
- setPercentilePosition(layoutParamsButtonX, 85, 40);
- setPercentilePosition(layoutParamsButtonY, 92, 35);
-
- setPercentilePosition(layoutParamsButtonLT, 95, 68);
- setPercentilePosition(layoutParamsButtonRT, 95, 80);
-
- setPercentilePosition(layoutParamsButtonLB, 85, 28);
- setPercentilePosition(layoutParamsButtonRB, 92, 23);
-
- setPercentilePosition(layoutParamsButtonSelect, 43, 94);
- setPercentilePosition(layoutParamsButtonStart, 57, 94);
-
- setPercentilePosition(layoutParamsButtonConfigure, 93, 7);
-
- relative_layout.addView(digitalPad, layoutParamsDPad);
-
- relative_layout.addView(stick, layoutParamsStick);
- relative_layout.addView(stick2, layoutParamsStick2);
-
- relative_layout.addView(buttonA, layoutParamsButtonA);
- relative_layout.addView(buttonB, layoutParamsButtonB);
- relative_layout.addView(buttonX, layoutParamsButtonX);
- relative_layout.addView(buttonY, layoutParamsButtonY);
- relative_layout.addView(buttonLT, layoutParamsButtonLT);
- relative_layout.addView(buttonRT, layoutParamsButtonRT);
- relative_layout.addView(buttonLB, layoutParamsButtonLB);
- relative_layout.addView(buttonRB, layoutParamsButtonRB);
-
- 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)
- {
- DigitalButton button = new DigitalButton(context);
- button.setText(text);
- button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener() {
- @Override
- public void onClick() {
- inputMap |= key;
- sendControllerInputPacket();
- }
-
- @Override
- public void onLongClick()
- {
-
- }
-
- @Override
- public void onRelease() {
- inputMap &= ~key;
- sendControllerInputPacket();
- }
- });
-
- return button;
- }
+ private DigitalButton buttonConfigure = null;
public VirtualController(final NvConnection conn, FrameLayout layout, final Context context)
{
- this.connection = conn;
- frame_layout = layout;
+ this.connection = conn;
+ this.frame_layout = layout;
+ this.context = context;
relative_layout = new RelativeLayout(context);
@@ -210,113 +86,113 @@ public class VirtualController
frame_layout.addView(relative_layout);
- digitalPad = new DigitalPad(context);
- digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener()
- {
- @Override
- public void onDirectionChange(int direction)
- {
- do
- {
- if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION)
- {
- inputMap &= ~ControllerPacket.LEFT_FLAG;
- inputMap &= ~ControllerPacket.RIGHT_FLAG;
- inputMap &= ~ControllerPacket.UP_FLAG;
- inputMap &= ~ControllerPacket.DOWN_FLAG;
+ digitalPad = new DigitalPad(context);
+ digitalPad.addDigitalPadListener(new DigitalPad.DigitalPadListener()
+ {
+ @Override
+ public void onDirectionChange(int direction)
+ {
+ do
+ {
+ if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION)
+ {
+ inputMap &= ~ControllerPacket.LEFT_FLAG;
+ inputMap &= ~ControllerPacket.RIGHT_FLAG;
+ inputMap &= ~ControllerPacket.UP_FLAG;
+ inputMap &= ~ControllerPacket.DOWN_FLAG;
- break;
- }
+ break;
+ }
- if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0)
- {
- inputMap |= ControllerPacket.LEFT_FLAG;
- }
+ if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0)
+ {
+ inputMap |= ControllerPacket.LEFT_FLAG;
+ }
- if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0)
- {
- inputMap |= ControllerPacket.RIGHT_FLAG;
- }
+ if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0)
+ {
+ inputMap |= ControllerPacket.RIGHT_FLAG;
+ }
- if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0)
- {
- inputMap |= ControllerPacket.UP_FLAG;
- }
+ if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0)
+ {
+ inputMap |= ControllerPacket.UP_FLAG;
+ }
- if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0)
- {
- inputMap |= ControllerPacket.DOWN_FLAG;
- }
- }
- while (false);
+ if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0)
+ {
+ inputMap |= ControllerPacket.DOWN_FLAG;
+ }
+ }
+ while (false);
- sendControllerInputPacket();
- }
- });
+ sendControllerInputPacket();
+ }
+ });
- buttonX = createDigitalButton("X", ControllerPacket.X_FLAG ,context);
- buttonY = createDigitalButton("Y", ControllerPacket.Y_FLAG ,context);
- buttonA = createDigitalButton("A", ControllerPacket.A_FLAG ,context);
- buttonB = createDigitalButton("B", ControllerPacket.B_FLAG ,context);
+ buttonX = createDigitalButton("X", ControllerPacket.X_FLAG, context);
+ buttonY = createDigitalButton("Y", ControllerPacket.Y_FLAG, context);
+ buttonA = createDigitalButton("A", ControllerPacket.A_FLAG, context);
+ buttonB = createDigitalButton("B", ControllerPacket.B_FLAG, context);
buttonLT = new DigitalButton(context);
buttonLT.setText("LT");
- buttonLT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
- {
- @Override
- public void onClick()
- {
- leftTrigger = (byte) (1 * 0xFF);
+ buttonLT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
+ {
+ @Override
+ public void onClick()
+ {
+ leftTrigger = (byte) (1 * 0xFF);
- sendControllerInputPacket();
- }
+ sendControllerInputPacket();
+ }
- @Override
- public void onLongClick()
- {
+ @Override
+ public void onLongClick()
+ {
- }
+ }
- @Override
- public void onRelease()
- {
- leftTrigger = (byte) (0 * 0xFF);
+ @Override
+ public void onRelease()
+ {
+ leftTrigger = (byte) (0 * 0xFF);
- sendControllerInputPacket();
- }
- });
+ sendControllerInputPacket();
+ }
+ });
buttonRT = new DigitalButton(context);
buttonRT.setText("RT");
- buttonRT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
- {
- @Override
- public void onClick()
- {
- rightTrigger = (byte) (0xFF);
+ buttonRT.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
+ {
+ @Override
+ public void onClick()
+ {
+ rightTrigger = (byte) (0xFF);
- sendControllerInputPacket();
- }
+ sendControllerInputPacket();
+ }
- @Override
- public void onLongClick()
- {
+ @Override
+ public void onLongClick()
+ {
- }
+ }
- @Override
- public void onRelease()
- {
- rightTrigger = (byte) (0);
+ @Override
+ public void onRelease()
+ {
+ rightTrigger = (byte) (0);
- sendControllerInputPacket();
- }
- });
+ sendControllerInputPacket();
+ }
+ });
- buttonLB = createDigitalButton("LB", ControllerPacket.LB_FLAG ,context);
- buttonRB = createDigitalButton("RB", ControllerPacket.RB_FLAG ,context);
+ buttonLB = createDigitalButton("LB", ControllerPacket.LB_FLAG, context);
+ buttonRB = createDigitalButton("RB", ControllerPacket.RB_FLAG, context);
- stick = new AnalogStick(context);
+ stick = new AnalogStick(context);
stick.addAnalogStickListener(new AnalogStick.AnalogStickListener()
{
@@ -326,30 +202,30 @@ public class VirtualController
leftStickX = (short) (x * 0x7FFE);
leftStickY = (short) (y * 0x7FFE);
- _DBG("LEFT STICK MOVEMENT X: "+ leftStickX + " Y: " + leftStickY);
+ _DBG("LEFT STICK MOVEMENT X: " + leftStickX + " Y: " + leftStickY);
sendControllerInputPacket();
}
- @Override
- public void onClick()
- {
- }
+ @Override
+ public void onClick()
+ {
+ }
- @Override
- public void onDoubleClick()
- {
- inputMap |= ControllerPacket.LS_CLK_FLAG;
+ @Override
+ public void onDoubleClick()
+ {
+ inputMap |= ControllerPacket.LS_CLK_FLAG;
- sendControllerInputPacket();
- }
+ sendControllerInputPacket();
+ }
- @Override
- public void onRevoke()
- {
- inputMap &= ~ControllerPacket.LS_CLK_FLAG;
+ @Override
+ public void onRevoke()
+ {
+ inputMap &= ~ControllerPacket.LS_CLK_FLAG;
- sendControllerInputPacket();
- }
+ sendControllerInputPacket();
+ }
});
stick2 = new AnalogStick(context);
@@ -361,83 +237,229 @@ public class VirtualController
rightStickX = (short) (x * 0x7FFE);
rightStickY = (short) (y * 0x7FFE);
- _DBG("RIGHT STICK MOVEMENT X: "+ rightStickX + " Y: " + rightStickY);
+ _DBG("RIGHT STICK MOVEMENT X: " + rightStickX + " Y: " + rightStickY);
sendControllerInputPacket();
}
- @Override
- public void onClick()
- {
- }
+ @Override
+ public void onClick()
+ {
+ }
- @Override
- public void onDoubleClick()
- {
- inputMap |= ControllerPacket.RS_CLK_FLAG;
+ @Override
+ public void onDoubleClick()
+ {
+ inputMap |= ControllerPacket.RS_CLK_FLAG;
- sendControllerInputPacket();
- }
+ sendControllerInputPacket();
+ }
- @Override
- public void onRevoke()
- {
- inputMap &= ~ControllerPacket.RS_CLK_FLAG;
+ @Override
+ public void onRevoke()
+ {
+ inputMap &= ~ControllerPacket.RS_CLK_FLAG;
- sendControllerInputPacket();
- }
- });
+ sendControllerInputPacket();
+ }
+ });
- buttonStart = createDigitalButton("START", ControllerPacket.PLAY_FLAG, context);
- buttonSelect = createDigitalButton("SELECT", ControllerPacket.SPECIAL_BUTTON_FLAG, context);
+ 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() {
+ 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);
+ @Override
+ public void onLongClick()
+ {
+ openSettingsDialog();
+ }
- virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ @Override
+ public void onRelease()
+ {
- context.startActivity(virtualControllerConfiguration);
-
- }
-
- @Override
- public void onRelease() {
-
- }
- });
+ }
+ });
refreshLayout();
}
+ private static final void _DBG(String text)
+ {
+ if (_PRINT_DEBUG_INFORMATION)
+ {
+ System.out.println("VirtualController: " + text);
+ }
+ }
+
+ private int getPercentageV(int percent)
+ {
+ return (int) (((float) frame_layout.getHeight() / (float) 100) * (float) percent);
+ }
+
+ private int getPercentageH(int percent)
+ {
+ return (int) (((float) frame_layout.getWidth() / (float) 100) * (float) percent);
+ }
+
+ private void setPercentilePosition(RelativeLayout.LayoutParams parm, float pos_x, float pos_y)
+ {
+ parm.setMargins(
+ (int) (((float) frame_layout.getWidth() / (float) 100 * pos_x) - ((float) parm.width / (float) 2)),
+ (int) (((float) frame_layout.getHeight() / (float) 100 * pos_y) - ((float) parm.height / (float) 2)),
+ 0,
+ 0
+ );
+ }
+
+ public void openSettingsDialog()
+ {
+ Intent virtualControllerConfiguration =
+ new Intent(context, VirtualControllerSettings.class);
+ virtualControllerConfiguration.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ context.startActivity(virtualControllerConfiguration);
+
+ }
+
+ void refreshLayout()
+ {
+ relative_layout.removeAllViews();
+
+ layoutParamsDPad =
+ new RelativeLayout.LayoutParams(getPercentageV(30), getPercentageV(30));
+
+ 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));
+ layoutParamsButtonX =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+ layoutParamsButtonY =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+ layoutParamsButtonLT =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+ layoutParamsButtonRT =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+
+ layoutParamsButtonLB =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+ layoutParamsButtonRB =
+ new RelativeLayout.LayoutParams(getPercentageV(10), getPercentageV(10));
+
+ 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(layoutParamsStick, 22, 78);
+ setPercentilePosition(layoutParamsStick2, 78, 78);
+
+ setPercentilePosition(layoutParamsButtonA, 85, 52);
+ setPercentilePosition(layoutParamsButtonB, 92, 47);
+ setPercentilePosition(layoutParamsButtonX, 85, 40);
+ setPercentilePosition(layoutParamsButtonY, 92, 35);
+
+ setPercentilePosition(layoutParamsButtonLT, 95, 68);
+ setPercentilePosition(layoutParamsButtonRT, 95, 80);
+
+ setPercentilePosition(layoutParamsButtonLB, 85, 28);
+ setPercentilePosition(layoutParamsButtonRB, 92, 23);
+
+ setPercentilePosition(layoutParamsButtonSelect, 43, 94);
+ setPercentilePosition(layoutParamsButtonStart, 57, 94);
+
+ setPercentilePosition(layoutParamsButtonConfigure, 93, 7);
+
+ relative_layout.addView(digitalPad, layoutParamsDPad);
+
+ relative_layout.addView(stick, layoutParamsStick);
+ relative_layout.addView(stick2, layoutParamsStick2);
+
+ relative_layout.addView(buttonA, layoutParamsButtonA);
+ relative_layout.addView(buttonB, layoutParamsButtonB);
+ relative_layout.addView(buttonX, layoutParamsButtonX);
+ relative_layout.addView(buttonY, layoutParamsButtonY);
+ relative_layout.addView(buttonLT, layoutParamsButtonLT);
+ relative_layout.addView(buttonRT, layoutParamsButtonRT);
+ relative_layout.addView(buttonLB, layoutParamsButtonLB);
+ relative_layout.addView(buttonRB, layoutParamsButtonRB);
+
+ 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)
+ {
+ DigitalButton button = new DigitalButton(context);
+ button.setText(text);
+ button.addDigitalButtonListener(new DigitalButton.DigitalButtonListener()
+ {
+ @Override
+ public void onClick()
+ {
+ inputMap |= key;
+ sendControllerInputPacket();
+ }
+
+ @Override
+ public void onLongClick()
+ {
+
+ }
+
+ @Override
+ public void onRelease()
+ {
+ inputMap &= ~key;
+ sendControllerInputPacket();
+ }
+ });
+
+ return button;
+ }
+
private void sendControllerInputPacket()
{
- try {
- _DBG("INPUT_MAP + " + inputMap);
- _DBG("LEFT_TRIGGER " + leftTrigger);
- _DBG("RIGHT_TRIGGER " + rightTrigger);
- _DBG("LEFT STICK X: " + leftStickX + " Y: " + leftStickY);
- _DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
- _DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
+ try
+ {
+ _DBG("INPUT_MAP + " + inputMap);
+ _DBG("LEFT_TRIGGER " + leftTrigger);
+ _DBG("RIGHT_TRIGGER " + rightTrigger);
+ _DBG("LEFT STICK X: " + leftStickX + " Y: " + leftStickY);
+ _DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
+ _DBG("RIGHT STICK X: " + rightStickX + " Y: " + rightStickY);
- if (connection != null)
- {
- connection.sendControllerInput(inputMap, leftTrigger, rightTrigger,
- leftStickX, leftStickY, rightStickX, rightStickY);
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
+ if (connection != null)
+ {
+ connection.sendControllerInput(inputMap, leftTrigger, rightTrigger,
+ leftStickX, leftStickY, rightStickX, rightStickY);
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
}
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 6d8ecbd9..25f952be 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
@@ -1,9 +1,7 @@
package com.limelight.binding.input.virtual_controller;
import android.app.Activity;
-import android.graphics.Color;
import android.os.Bundle;
-import android.os.PersistableBundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -16,29 +14,30 @@ import com.limelight.R;
*/
public class VirtualControllerConfiguration extends Activity
{
- VirtualController virtualController;
+ VirtualController virtualController;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
- // We don't want a title bar
- requestWindowFeature(Window.FEATURE_NO_TITLE);
+ // We don't want a title bar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
- // Full-screen and don't let the display go off
- getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_FULLSCREEN |
- WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ // Full-screen and don't let the display go off
+ getWindow().addFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN |
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- // Inflate the content
- setContentView(R.layout.activity_configure_virtual_controller);
+ // Inflate the content
+ setContentView(R.layout.activity_configure_virtual_controller);
- FrameLayout frameLayout = (FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout);
+ FrameLayout frameLayout =
+ (FrameLayout) findViewById(R.id.configure_virtual_controller_frameLayout);
- // start with configuration constructor
- virtualController = new VirtualController(null, frameLayout, this);
+ // start with configuration constructor
+ virtualController = new VirtualController(null, frameLayout, this);
- Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
- }
+ Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
+ }
}
diff --git a/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerElement.java b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerElement.java
new file mode 100644
index 00000000..72e30c32
--- /dev/null
+++ b/app/src/main/java/com/limelight/binding/input/virtual_controller/VirtualControllerElement.java
@@ -0,0 +1,45 @@
+package com.limelight.binding.input.virtual_controller;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * Created by Karim on 27.01.2015.
+ */
+public abstract class VirtualControllerElement extends View
+{
+ protected static boolean _PRINT_DEBUG_INFORMATION = false;
+ protected int normalColor = 0xF0888888;
+ protected int pressedColor = 0xF00000FF;
+
+ protected VirtualControllerElement(Context context)
+ {
+ super(context);
+ }
+
+ protected static final void _DBG(String text)
+ {
+ if (_PRINT_DEBUG_INFORMATION)
+ {
+ System.out.println("DigitalButton: " + text);
+ }
+ }
+
+ public void setColors(int normalColor, int pressedColor)
+ {
+ this.normalColor = normalColor;
+ this.pressedColor = pressedColor;
+
+ invalidate();
+ }
+
+ protected final float getPercent(float value, float percent)
+ {
+ return value / 100 * percent;
+ }
+
+ protected final int getCorrectWidth()
+ {
+ return getWidth() > getHeight() ? getHeight() : getWidth();
+ }
+}
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
index 3432b63e..621d9b19 100644
--- 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
@@ -2,46 +2,28 @@ 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;
+ private VirtualController controller = null;
- static void setController(VirtualController value)
- {
- controller = value;
- }
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ // We don't want a title bar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
- static void setView(View value)
- {
- view = value;
- }
+ // Inflate the content
+ setContentView(R.layout.activity_virtual_controller_settings);
- @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();
- }
+ Toast.makeText(getApplicationContext(), "Not implemented yet!", Toast.LENGTH_SHORT).show();
+ }
}
diff --git a/app/src/main/java/com/limelight/computers/ComputerManagerService.java b/app/src/main/java/com/limelight/computers/ComputerManagerService.java
index 182ff690..afafbe58 100644
--- a/app/src/main/java/com/limelight/computers/ComputerManagerService.java
+++ b/app/src/main/java/com/limelight/computers/ComputerManagerService.java
@@ -251,6 +251,11 @@ public class ComputerManagerService extends Service {
((!details.name.isEmpty() && !tuple.computer.name.isEmpty()) &&
tuple.computer.name.equals(details.name))) {
+ // Update details anyway in case this machine has been re-added by IP
+ // after not being reachable by our existing information
+ tuple.computer.localIp = details.localIp;
+ tuple.computer.remoteIp = details.remoteIp;
+
// Start a polling thread if polling is active
if (pollingActive && tuple.thread == null) {
tuple.thread = createPollingThread(details);
diff --git a/app/src/main/java/com/limelight/grid/AppGridAdapter.java b/app/src/main/java/com/limelight/grid/AppGridAdapter.java
index c2d1624b..199eaf03 100644
--- a/app/src/main/java/com/limelight/grid/AppGridAdapter.java
+++ b/app/src/main/java/com/limelight/grid/AppGridAdapter.java
@@ -1,16 +1,30 @@
package com.limelight.grid;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.widget.TextView;
import com.koushikdutta.async.future.FutureCallback;
+import com.koushikdutta.ion.ImageViewBitmapInfo;
import com.koushikdutta.ion.Ion;
+import com.koushikdutta.ion.bitmap.BitmapInfo;
import com.limelight.AppView;
+import com.limelight.LimeLog;
import com.limelight.R;
import com.limelight.binding.PlatformBinding;
import com.limelight.nvstream.http.LimelightCryptoProvider;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
@@ -32,14 +46,15 @@ import java.security.cert.X509Certificate;
public class AppGridAdapter extends GenericGridAdapter {
+ private boolean listMode;
private InetAddress address;
private String uniqueId;
private LimelightCryptoProvider cryptoProvider;
private SSLContext sslContext;
private final HashMap pendingRequests = new HashMap();
- public AppGridAdapter(Context context, InetAddress address, String uniqueId) throws NoSuchAlgorithmException, KeyManagementException {
- super(context, R.layout.app_grid_item, R.drawable.image_loading);
+ public AppGridAdapter(Context context, boolean listMode, InetAddress address, String uniqueId) throws NoSuchAlgorithmException, KeyManagementException {
+ super(context, listMode ? R.layout.simple_row : R.layout.app_grid_item, R.drawable.image_loading);
this.address = address;
this.uniqueId = uniqueId;
@@ -107,7 +122,9 @@ public class AppGridAdapter extends GenericGridAdapter {
}
for (Future f : tempMap.values()) {
- f.cancel(true);
+ if (!f.isCancelled() && !f.isDone()) {
+ f.cancel(true);
+ }
}
synchronized (pendingRequests) {
@@ -118,28 +135,92 @@ public class AppGridAdapter extends GenericGridAdapter {
}
}
+ private Bitmap checkBitmapCache(String addrStr, int appId) {
+ File addrFolder = new File(context.getCacheDir(), addrStr);
+ if (addrFolder.isDirectory()) {
+ File bitmapFile = new File(addrFolder, appId+".png");
+ if (bitmapFile.exists()) {
+ InputStream fileIn = null;
+ try {
+ fileIn = new BufferedInputStream(new FileInputStream(bitmapFile));
+ Bitmap bm = BitmapFactory.decodeStream(fileIn);
+ if (bm == null) {
+ // The image seems corrupt
+ bitmapFile.delete();
+ }
+
+ return bm;
+ } catch (IOException e) {
+ e.printStackTrace();
+ bitmapFile.delete();
+ } finally {
+ if (fileIn != null) {
+ try {
+ fileIn.close();
+ } catch (IOException ignored) {}
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ // TODO: Handle pruning of bitmap cache
+ private void populateBitmapCache(String addrStr, int appId, Bitmap bitmap) {
+ File addrFolder = new File(context.getCacheDir(), addrStr);
+ addrFolder.mkdirs();
+
+ File bitmapFile = new File(addrFolder, appId+".png");
+ try {
+ // PNG ignores quality setting
+ bitmap.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(bitmapFile));
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
@Override
- public boolean populateImageView(final ImageView imgView, AppView.AppObject obj) {
+ public boolean populateImageView(final ImageView imgView, final AppView.AppObject obj) {
// Set SSL contexts correctly to allow us to authenticate
Ion.getDefault(imgView.getContext()).getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustAllCerts);
Ion.getDefault(imgView.getContext()).getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext);
- // Set off the deferred image load
+ // Check the on-disk cache
+ Bitmap cachedBitmap = checkBitmapCache(address.getHostAddress(), obj.app.getAppId());
+ if (cachedBitmap != null) {
+ // Cache hit; we're done
+ LimeLog.info("Image cache hit for ("+address.getHostAddress()+", "+obj.app.getAppId()+")");
+ imgView.setImageBitmap(cachedBitmap);
+ return true;
+ }
+
+ // Kick off the deferred image load
synchronized (pendingRequests) {
- Future f = Ion.with(imgView)
+ Future f = Ion.with(imgView)
.placeholder(defaultImageRes)
.error(defaultImageRes)
.load("https://" + address.getHostAddress() + ":47984/appasset?uniqueid=" + uniqueId + "&appid=" +
obj.app.getAppId() + "&AssetType=2&AssetIdx=0")
- .setCallback(new FutureCallback() {
- @Override
- public void onCompleted(Exception e, ImageView result) {
- synchronized (pendingRequests) {
- pendingRequests.remove(imgView);
- }
- }
- });
+ .withBitmapInfo()
+ .setCallback(
+ new FutureCallback() {
+ @Override
+ public void onCompleted(Exception e, ImageViewBitmapInfo result) {
+ synchronized (pendingRequests) {
+ pendingRequests.remove(imgView);
+ }
+
+ // Populate the cache if we got an image back
+ if (result != null &&
+ result.getBitmapInfo() != null &&
+ result.getBitmapInfo().bitmap != null) {
+ populateBitmapCache(address.getHostAddress(), obj.app.getAppId(),
+ result.getBitmapInfo().bitmap);
+ }
+ }
+ });
pendingRequests.put(imgView, f);
}
diff --git a/app/src/main/java/com/limelight/grid/GenericGridAdapter.java b/app/src/main/java/com/limelight/grid/GenericGridAdapter.java
index d2d68a14..f0a17618 100644
--- a/app/src/main/java/com/limelight/grid/GenericGridAdapter.java
+++ b/app/src/main/java/com/limelight/grid/GenericGridAdapter.java
@@ -60,17 +60,21 @@ public abstract class GenericGridAdapter extends BaseAdapter {
ImageView overlayView = (ImageView) convertView.findViewById(R.id.grid_overlay);
TextView txtView = (TextView) convertView.findViewById(R.id.grid_text);
- if (!populateImageView(imgView, itemList.get(i))) {
- imgView.setImageResource(defaultImageRes);
+ if (imgView != null) {
+ if (!populateImageView(imgView, itemList.get(i))) {
+ imgView.setImageResource(defaultImageRes);
+ }
}
if (!populateTextView(txtView, itemList.get(i))) {
txtView.setText(itemList.get(i).toString());
}
- if (!populateOverlayView(overlayView, itemList.get(i))) {
- overlayView.setVisibility(View.INVISIBLE);
- }
- else {
- overlayView.setVisibility(View.VISIBLE);
+ if (overlayView != null) {
+ if (!populateOverlayView(overlayView, itemList.get(i))) {
+ overlayView.setVisibility(View.INVISIBLE);
+ }
+ else {
+ overlayView.setVisibility(View.VISIBLE);
+ }
}
return convertView;
diff --git a/app/src/main/java/com/limelight/grid/PcGridAdapter.java b/app/src/main/java/com/limelight/grid/PcGridAdapter.java
index a191381c..8e370de3 100644
--- a/app/src/main/java/com/limelight/grid/PcGridAdapter.java
+++ b/app/src/main/java/com/limelight/grid/PcGridAdapter.java
@@ -8,14 +8,27 @@ import com.limelight.PcView;
import com.limelight.R;
import com.limelight.nvstream.http.ComputerDetails;
+import java.util.Collections;
+import java.util.Comparator;
+
public class PcGridAdapter extends GenericGridAdapter {
- public PcGridAdapter(Context context) {
- super(context, R.layout.pc_grid_item, R.drawable.computer);
+ public PcGridAdapter(Context context, boolean listMode) {
+ super(context, listMode ? R.layout.simple_row : R.layout.pc_grid_item, R.drawable.computer);
}
public void addComputer(PcView.ComputerObject computer) {
itemList.add(computer);
+ sortList();
+ }
+
+ private void sortList() {
+ Collections.sort(itemList, new Comparator() {
+ @Override
+ public int compare(PcView.ComputerObject lhs, PcView.ComputerObject rhs) {
+ return lhs.details.name.compareTo(rhs.details.name);
+ }
+ });
}
public boolean removeComputer(PcView.ComputerObject computer) {
diff --git a/app/src/main/java/com/limelight/preferences/AddComputerManually.java b/app/src/main/java/com/limelight/preferences/AddComputerManually.java
index 9e8b1584..c2eaa19a 100644
--- a/app/src/main/java/com/limelight/preferences/AddComputerManually.java
+++ b/app/src/main/java/com/limelight/preferences/AddComputerManually.java
@@ -2,6 +2,7 @@ package com.limelight.preferences;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Locale;
import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.computers.ComputerManagerService;
@@ -15,8 +16,10 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
+import android.preference.Preference;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
@@ -132,6 +135,13 @@ public class AddComputerManually extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ String locale = PreferenceConfiguration.readPreferences(this).language;
+ if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
+ Configuration config = new Configuration(getResources().getConfiguration());
+ config.locale = new Locale(locale);
+ getResources().updateConfiguration(config, getResources().getDisplayMetrics());
+ }
+
setContentView(R.layout.activity_add_computer_manually);
UiHelper.notifyNewRootView(this);
diff --git a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
index 50f0159a..73aee4a3 100644
--- a/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
+++ b/app/src/main/java/com/limelight/preferences/PreferenceConfiguration.java
@@ -13,6 +13,8 @@ public class PreferenceConfiguration {
private static final String DISABLE_TOASTS_PREF_STRING = "checkbox_disable_warnings";
private static final String HOST_AUDIO_PREF_STRING = "checkbox_host_audio";
private static final String DEADZONE_PREF_STRING = "seekbar_deadzone";
+ private static final String LANGUAGE_PREF_STRING = "list_languages";
+ private static final String LIST_MODE_PREF_STRING = "checkbox_list_mode";
private static final String VIRTUAL_CONTROLLER_ENABLE = "virtual_controller_checkbox_enable";
private static final Boolean VIRTUAL_CONTROLLER_ENABLE_DEFAULT = true;
@@ -30,6 +32,8 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_DISABLE_TOASTS = false;
private static final boolean DEFAULT_HOST_AUDIO = false;
private static final int DEFAULT_DEADZONE = 15;
+ public static final String DEFAULT_LANGUAGE = "default";
+ private static final boolean DEFAULT_LIST_MODE = false;
public static final int FORCE_HARDWARE_DECODER = -1;
public static final int AUTOSELECT_DECODER = 0;
@@ -40,6 +44,8 @@ public class PreferenceConfiguration {
public int decoder;
public int deadzonePercentage;
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
+ public String language;
+ public boolean listMode;
public boolean virtualController_enable;
@@ -140,11 +146,14 @@ public class PreferenceConfiguration {
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
+ config.language = prefs.getString(LANGUAGE_PREF_STRING, DEFAULT_LANGUAGE);
+
// Checkbox preferences
config.disableWarnings = prefs.getBoolean(DISABLE_TOASTS_PREF_STRING, DEFAULT_DISABLE_TOASTS);
config.enableSops = prefs.getBoolean(SOPS_PREF_STRING, DEFAULT_SOPS);
config.stretchVideo = prefs.getBoolean(STRETCH_PREF_STRING, DEFAULT_STRETCH);
config.playHostAudio = prefs.getBoolean(HOST_AUDIO_PREF_STRING, DEFAULT_HOST_AUDIO);
+ config.listMode = prefs.getBoolean(LIST_MODE_PREF_STRING, DEFAULT_LIST_MODE);
config.virtualController_enable = prefs.getBoolean(VIRTUAL_CONTROLLER_ENABLE, VIRTUAL_CONTROLLER_ENABLE_DEFAULT);
diff --git a/app/src/main/java/com/limelight/preferences/StreamSettings.java b/app/src/main/java/com/limelight/preferences/StreamSettings.java
index 5b9e361f..821e7449 100644
--- a/app/src/main/java/com/limelight/preferences/StreamSettings.java
+++ b/app/src/main/java/com/limelight/preferences/StreamSettings.java
@@ -2,22 +2,33 @@ package com.limelight.preferences;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.app.Activity;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
+import com.limelight.PcView;
import com.limelight.R;
import com.limelight.binding.input.virtual_controller.VirtualController;
import com.limelight.binding.input.virtual_controller.VirtualControllerConfiguration;
import com.limelight.utils.UiHelper;
+import java.util.Locale;
+
public class StreamSettings extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ String locale = PreferenceConfiguration.readPreferences(this).language;
+ if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
+ Configuration config = new Configuration(getResources().getConfiguration());
+ config.locale = new Locale(locale);
+ getResources().updateConfiguration(config, getResources().getDisplayMetrics());
+ }
+
setContentView(R.layout.activity_stream_settings);
getFragmentManager().beginTransaction().replace(
R.id.stream_settings, new SettingsFragment()
@@ -26,6 +37,16 @@ public class StreamSettings extends Activity {
UiHelper.notifyNewRootView(this);
}
+ @Override
+ public void onBackPressed() {
+ finish();
+
+ // Restart the PC view to apply UI changes
+ Intent intent = new Intent(this, PcView.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent, null);
+ }
+
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/app/src/main/java/com/limelight/ui/AdapterFragment.java b/app/src/main/java/com/limelight/ui/AdapterFragment.java
new file mode 100644
index 00000000..8076fa06
--- /dev/null
+++ b/app/src/main/java/com/limelight/ui/AdapterFragment.java
@@ -0,0 +1,35 @@
+package com.limelight.ui;
+
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+
+import com.limelight.R;
+
+public class AdapterFragment extends Fragment {
+ private AdapterFragmentCallbacks callbacks;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ callbacks = (AdapterFragmentCallbacks) activity;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(callbacks.getAdapterFragmentLayoutId(), container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ callbacks.receiveAbsListView((AbsListView) getView().findViewById(R.id.fragmentView));
+ }
+}
diff --git a/app/src/main/java/com/limelight/ui/AdapterFragmentCallbacks.java b/app/src/main/java/com/limelight/ui/AdapterFragmentCallbacks.java
new file mode 100644
index 00000000..4ebade79
--- /dev/null
+++ b/app/src/main/java/com/limelight/ui/AdapterFragmentCallbacks.java
@@ -0,0 +1,8 @@
+package com.limelight.ui;
+
+import android.widget.AbsListView;
+
+public interface AdapterFragmentCallbacks {
+ public int getAdapterFragmentLayoutId();
+ public void receiveAbsListView(AbsListView gridView);
+}
diff --git a/app/src/main/java/com/limelight/ui/GameGestures.java b/app/src/main/java/com/limelight/ui/GameGestures.java
new file mode 100644
index 00000000..4589ecc9
--- /dev/null
+++ b/app/src/main/java/com/limelight/ui/GameGestures.java
@@ -0,0 +1,5 @@
+package com.limelight.ui;
+
+public interface GameGestures {
+ public void showKeyboard();
+}
diff --git a/app/src/main/res/drawable/list_view_unselected.xml b/app/src/main/res/drawable/list_view_unselected.xml
new file mode 100644
index 00000000..b691f3a2
--- /dev/null
+++ b/app/src/main/res/drawable/list_view_unselected.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/activity_pc_view.xml b/app/src/main/res/layout-land/activity_pc_view.xml
index 91169932..523341b9 100644
--- a/app/src/main/res/layout-land/activity_pc_view.xml
+++ b/app/src/main/res/layout-land/activity_pc_view.xml
@@ -33,12 +33,10 @@
android:text="@string/searching_pc"/>
-
-
-
-
+ android:layout_below="@+id/appListText"/>
@@ -93,7 +93,8 @@
android:text="Color 2"/>
diff --git a/app/src/main/res/layout/app_grid_view.xml b/app/src/main/res/layout/app_grid_view.xml
new file mode 100644
index 00000000..6926a933
--- /dev/null
+++ b/app/src/main/res/layout/app_grid_view.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_view.xml b/app/src/main/res/layout/list_view.xml
new file mode 100644
index 00000000..c41508ee
--- /dev/null
+++ b/app/src/main/res/layout/list_view.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/pc_grid_view.xml b/app/src/main/res/layout/pc_grid_view.xml
new file mode 100644
index 00000000..98a0c9cd
--- /dev/null
+++ b/app/src/main/res/layout/pc_grid_view.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/simple_row.xml b/app/src/main/res/layout/simple_row.xml
new file mode 100644
index 00000000..92ba894d
--- /dev/null
+++ b/app/src/main/res/layout/simple_row.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 77cb9740..705bd4f4 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -94,11 +94,17 @@
Aggiusta deadzone degli stick analogici
%
+ UI Settings
+ Lingua
+ Lingua da usare in Limelight
+ Use lists instead of grids
+ Display apps and PCs in lists instead of grids
+
Impostazioni Host
Ottimizza le impostazioni dei giochi
Permetti a GFE di modificare le impostazioni dei giochi per uno streaming ottimale
Riproduci audio sul PC
- Riproduci l\'audio sul computer e su questo dispositivo. Richiede GFE 2.1.2+
+ Riproduci l\'audio sul computer e su questo dispositivo
Impostazioni Avanzate
Cambia decoder
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 73df0415..44a32405 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -13,6 +13,17 @@
- 1080p60
+
+ - Default
+ - English
+ - Italiano
+
+
+ - default
+ - en
+ - it
+
+
- Auto-select Decoder
- Force Software Decoding
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ccd9898e..b9a58ee2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -94,11 +94,17 @@
Adjust analog stick deadzone
%
+ UI Settings
+ Language
+ Language to use for Limelight
+ Use lists instead of grids
+ Display apps and PCs in lists instead of grids
+
Host Settings
Optimize game settings
Allow GFE to modify game settings for optimal streaming
Play audio on PC
- Play audio from the computer and this device. Requires GFE 2.1.2+
+ Play audio from the computer and this device
Advanced Settings
Change decoder
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index d5c608e9..91563473 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -46,6 +46,20 @@
android:summary="@string/summary_checkbox_host_audio"
android:defaultValue="false" />
+
+
+
+
-
\ No newline at end of file
+