mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-21 15:56:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9e811862a | ||
|
|
25ccc3d0e1 | ||
|
|
8853bf0670 | ||
|
|
71fa3a824b | ||
|
|
56fd50834c | ||
|
|
48ba812cf6 | ||
|
|
019dc6d45f | ||
|
|
cbcb784a79 | ||
|
|
39fa0258ad | ||
|
|
d0dd5bfa8c | ||
|
|
b948c47618 | ||
|
|
18cae8ac53 | ||
|
|
0576231dfc | ||
|
|
6ad35a83dd | ||
|
|
33d4dfc745 | ||
|
|
f3bf63a668 | ||
|
|
2dbb7395a4 | ||
|
|
7c1eb80d62 | ||
|
|
f2bf093691 | ||
|
|
2f002bfa4a | ||
|
|
4a19038d54 | ||
|
|
15fb3dd92c | ||
|
|
e0982d3961 | ||
|
|
7fb2f15f54 | ||
|
|
f93dbb4116 | ||
|
|
bc34fe3a9f | ||
|
|
bbe49491c1 | ||
|
|
d5ccb80f26 | ||
|
|
50fd15379a | ||
|
|
ed479f1155 | ||
|
|
04db9ba714 | ||
|
|
6a973e3248 | ||
|
|
96d9e4977b | ||
|
|
5a3897f22a | ||
|
|
ceef00b79a |
No files matched your search
+3
-3
@@ -5,14 +5,14 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 23
|
||||||
buildToolsVersion "23.0.2"
|
buildToolsVersion "23.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
|
|
||||||
versionName "4.5.4"
|
versionName "4.5.9"
|
||||||
versionCode = 91
|
versionCode = 100
|
||||||
}
|
}
|
||||||
|
|
||||||
productFlavors {
|
productFlavors {
|
||||||
|
|||||||
Binary file not shown.
@@ -37,7 +37,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".AppView"
|
android:name=".AppView"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection" >
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.limelight.PcView" />
|
android:value="com.limelight.PcView" />
|
||||||
|
|||||||
@@ -96,9 +96,25 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
// Load the app grid with cached data (if possible)
|
// Load the app grid with cached data (if possible)
|
||||||
populateAppGridWithCache();
|
populateAppGridWithCache();
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
runOnUiThread(new Runnable() {
|
||||||
.replace(R.id.appFragmentContainer, new AdapterFragment())
|
@Override
|
||||||
.commitAllowingStateLoss();
|
public void run() {
|
||||||
|
if (isFinishing() || isChangingConfigurations()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Despite my best efforts to catch all conditions that could
|
||||||
|
// cause the activity to be destroyed when we try to commit
|
||||||
|
// I haven't been able to, so we have this try-catch block.
|
||||||
|
try {
|
||||||
|
getFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.appFragmentContainer, new AdapterFragment())
|
||||||
|
.commitAllowingStateLoss();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.limelight.nvstream.input.KeyboardPacket;
|
|||||||
import com.limelight.nvstream.input.MouseButtonPacket;
|
import com.limelight.nvstream.input.MouseButtonPacket;
|
||||||
import com.limelight.preferences.PreferenceConfiguration;
|
import com.limelight.preferences.PreferenceConfiguration;
|
||||||
import com.limelight.ui.GameGestures;
|
import com.limelight.ui.GameGestures;
|
||||||
|
import com.limelight.ui.StreamView;
|
||||||
import com.limelight.utils.Dialog;
|
import com.limelight.utils.Dialog;
|
||||||
import com.limelight.utils.SpinnerDialog;
|
import com.limelight.utils.SpinnerDialog;
|
||||||
|
|
||||||
@@ -74,8 +75,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private final TouchContext[] touchContextMap = new TouchContext[2];
|
private final TouchContext[] touchContextMap = new TouchContext[2];
|
||||||
private long threeFingerDownTime = 0;
|
private long threeFingerDownTime = 0;
|
||||||
|
|
||||||
private static final double REFERENCE_HORIZ_RES = 1280;
|
private static final int REFERENCE_HORIZ_RES = 1280;
|
||||||
private static final double REFERENCE_VERT_RES = 720;
|
private static final int REFERENCE_VERT_RES = 720;
|
||||||
|
|
||||||
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
|
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
|
||||||
|
|
||||||
@@ -84,19 +85,18 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private KeyboardTranslator keybTranslator;
|
private KeyboardTranslator keybTranslator;
|
||||||
|
|
||||||
private PreferenceConfiguration prefConfig;
|
private PreferenceConfiguration prefConfig;
|
||||||
private final Point screenSize = new Point(0, 0);
|
|
||||||
|
|
||||||
private NvConnection conn;
|
private NvConnection conn;
|
||||||
private SpinnerDialog spinner;
|
private SpinnerDialog spinner;
|
||||||
private boolean displayedFailureDialog = false;
|
private boolean displayedFailureDialog = false;
|
||||||
private boolean connecting = false;
|
private boolean connecting = false;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
private boolean deferredSurfaceResize = false;
|
|
||||||
|
|
||||||
private EvdevHandler evdevHandler;
|
private EvdevHandler evdevHandler;
|
||||||
private int modifierFlags = 0;
|
private int modifierFlags = 0;
|
||||||
private boolean grabbedInput = true;
|
private boolean grabbedInput = true;
|
||||||
private boolean grabComboDown = false;
|
private boolean grabComboDown = false;
|
||||||
|
private StreamView streamView;
|
||||||
|
|
||||||
private EnhancedDecoderRenderer decoderRenderer;
|
private EnhancedDecoderRenderer decoderRenderer;
|
||||||
|
|
||||||
@@ -175,13 +175,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
drFlags |= VideoDecoderRenderer.FLAG_FILL_SCREEN;
|
drFlags |= VideoDecoderRenderer.FLAG_FILL_SCREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
Display display = getWindowManager().getDefaultDisplay();
|
|
||||||
display.getSize(screenSize);
|
|
||||||
|
|
||||||
// Listen for events on the game surface
|
// Listen for events on the game surface
|
||||||
SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView);
|
streamView = (StreamView) findViewById(R.id.surfaceView);
|
||||||
sv.setOnGenericMotionListener(this);
|
streamView.setOnGenericMotionListener(this);
|
||||||
sv.setOnTouchListener(this);
|
streamView.setOnTouchListener(this);
|
||||||
|
|
||||||
// Warn the user if they're on a metered connection
|
// Warn the user if they're on a metered connection
|
||||||
checkDataConnection();
|
checkDataConnection();
|
||||||
@@ -258,6 +255,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
// >= 4K screens have exactly 4K screens, so we'll be able to hit this good path
|
||||||
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
// on these devices. On Marshmallow, we can start changing to 4K manually but no
|
||||||
// 4K devices run 6.0 at the moment.
|
// 4K devices run 6.0 at the moment.
|
||||||
|
Display display = getWindowManager().getDefaultDisplay();
|
||||||
|
Point screenSize = new Point(0, 0);
|
||||||
|
display.getSize(screenSize);
|
||||||
|
|
||||||
double screenAspectRatio = ((double)screenSize.y) / screenSize.x;
|
double screenAspectRatio = ((double)screenSize.y) / screenSize.x;
|
||||||
double streamAspectRatio = ((double)prefConfig.height) / prefConfig.width;
|
double streamAspectRatio = ((double)prefConfig.height) / prefConfig.width;
|
||||||
if (Math.abs(screenAspectRatio - streamAspectRatio) < 0.001) {
|
if (Math.abs(screenAspectRatio - streamAspectRatio) < 0.001) {
|
||||||
@@ -266,20 +267,21 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceHolder sh = sv.getHolder();
|
SurfaceHolder sh = streamView.getHolder();
|
||||||
if (prefConfig.stretchVideo || aspectRatioMatch) {
|
if (prefConfig.stretchVideo || aspectRatioMatch) {
|
||||||
// Set the surface to the size of the video
|
// Set the surface to the size of the video
|
||||||
sh.setFixedSize(prefConfig.width, prefConfig.height);
|
sh.setFixedSize(prefConfig.width, prefConfig.height);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deferredSurfaceResize = true;
|
// Set the surface to scale based on the aspect ratio of the stream
|
||||||
|
streamView.setDesiredAspectRatio((double)prefConfig.width / (double)prefConfig.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize touch contexts
|
// Initialize touch contexts
|
||||||
for (int i = 0; i < touchContextMap.length; i++) {
|
for (int i = 0; i < touchContextMap.length; i++) {
|
||||||
touchContextMap[i] = new TouchContext(conn, i,
|
touchContextMap[i] = new TouchContext(conn, i,
|
||||||
(REFERENCE_HORIZ_RES / (double)screenSize.x),
|
REFERENCE_HORIZ_RES, REFERENCE_VERT_RES,
|
||||||
(REFERENCE_VERT_RES / (double)screenSize.y));
|
streamView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LimelightBuildProps.ROOT_BUILD) {
|
if (LimelightBuildProps.ROOT_BUILD) {
|
||||||
@@ -306,26 +308,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
sh.addCallback(this);
|
sh.addCallback(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizeSurfaceWithAspectRatio(SurfaceView sv, double vidWidth, double vidHeight)
|
|
||||||
{
|
|
||||||
// Get the visible width of the activity
|
|
||||||
double visibleWidth = getWindow().getDecorView().getWidth();
|
|
||||||
|
|
||||||
ViewGroup.LayoutParams lp = sv.getLayoutParams();
|
|
||||||
|
|
||||||
// Calculate the new size of the SurfaceView
|
|
||||||
lp.width = (int) visibleWidth;
|
|
||||||
lp.height = (int) ((vidHeight / vidWidth) * visibleWidth);
|
|
||||||
|
|
||||||
// Apply the size change
|
|
||||||
sv.setLayoutParams(lp);
|
|
||||||
|
|
||||||
// refresh virtual controller layout
|
|
||||||
if (virtualController != null) {
|
|
||||||
virtualController.refreshLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkDataConnection()
|
private void checkDataConnection()
|
||||||
{
|
{
|
||||||
ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
ConnectivityManager mgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
@@ -802,8 +784,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
// Scale the deltas if the device resolution is different
|
// Scale the deltas if the device resolution is different
|
||||||
// than the stream resolution
|
// than the stream resolution
|
||||||
deltaX = (int)Math.round((double)deltaX * (REFERENCE_HORIZ_RES / (double)screenSize.x));
|
deltaX = (int)Math.round((double)deltaX * (REFERENCE_HORIZ_RES / (double)streamView.getWidth()));
|
||||||
deltaY = (int)Math.round((double)deltaY * (REFERENCE_VERT_RES / (double)screenSize.y));
|
deltaY = (int)Math.round((double)deltaY * (REFERENCE_VERT_RES / (double)streamView.getHeight()));
|
||||||
|
|
||||||
conn.sendMouseMove((short)deltaX, (short)deltaY);
|
conn.sendMouseMove((short)deltaX, (short)deltaY);
|
||||||
}
|
}
|
||||||
@@ -932,13 +914,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
if (!connected && !connecting) {
|
if (!connected && !connecting) {
|
||||||
connecting = true;
|
connecting = true;
|
||||||
|
|
||||||
// Resize the surface to match the aspect ratio of the video
|
|
||||||
// This must be done after the surface is created.
|
|
||||||
if (deferredSurfaceResize) {
|
|
||||||
resizeSurfaceWithAspectRatio((SurfaceView) findViewById(R.id.surfaceView),
|
|
||||||
prefConfig.width, prefConfig.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
||||||
PlatformBinding.getAudioRenderer(), decoderRenderer);
|
PlatformBinding.getAudioRenderer(), decoderRenderer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
Dialog.displayDialog(PcView.this, getResources().getString(R.string.pair_pairing_title),
|
Dialog.displayDialog(PcView.this, getResources().getString(R.string.pair_pairing_title),
|
||||||
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr, false);
|
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr, false);
|
||||||
|
|
||||||
PairingManager.PairState pairState = httpConn.pair(pinStr);
|
PairingManager.PairState pairState = httpConn.pair(httpConn.getServerInfo(), pinStr);
|
||||||
if (pairState == PairingManager.PairState.PIN_WRONG) {
|
if (pairState == PairingManager.PairState.PIN_WRONG) {
|
||||||
message = getResources().getString(R.string.pair_incorrect_pin);
|
message = getResources().getString(R.string.pair_incorrect_pin);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
defaultContext.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
|
defaultContext.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
|
||||||
defaultContext.rightTriggerAxis = MotionEvent.AXIS_GAS;
|
defaultContext.rightTriggerAxis = MotionEvent.AXIS_GAS;
|
||||||
defaultContext.controllerNumber = (short) 0;
|
defaultContext.controllerNumber = (short) 0;
|
||||||
|
defaultContext.assignedControllerNumber = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
|
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
|
||||||
@@ -146,8 +147,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
InputDeviceContext devContext = (InputDeviceContext) context;
|
InputDeviceContext devContext = (InputDeviceContext) context;
|
||||||
|
|
||||||
LimeLog.info(devContext.name+" ("+context.id+") needs a controller number assigned");
|
LimeLog.info(devContext.name+" ("+context.id+") needs a controller number assigned");
|
||||||
if (devContext.name != null && devContext.name.contains("gpio-keys")) {
|
if (devContext.name != null &&
|
||||||
// This is the back button on Shield portable consoles
|
(devContext.name.contains("gpio-keys") || // This is the back button on Shield portable consoles
|
||||||
|
devContext.name.contains("joy_key"))) { // These are the gamepad buttons on the Archos Gamepad 2
|
||||||
LimeLog.info("Built-in buttons hardcoded as controller 0");
|
LimeLog.info("Built-in buttons hardcoded as controller 0");
|
||||||
context.controllerNumber = 0;
|
context.controllerNumber = 0;
|
||||||
}
|
}
|
||||||
@@ -212,6 +214,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
String devName = dev.getName();
|
String devName = dev.getName();
|
||||||
|
|
||||||
LimeLog.info("Creating controller context for device: "+devName);
|
LimeLog.info("Creating controller context for device: "+devName);
|
||||||
|
LimeLog.info(dev.toString());
|
||||||
|
|
||||||
context.name = devName;
|
context.name = devName;
|
||||||
context.id = dev.getId();
|
context.id = dev.getId();
|
||||||
@@ -229,6 +232,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
InputDevice.MotionRange rightTriggerRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RTRIGGER);
|
InputDevice.MotionRange rightTriggerRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RTRIGGER);
|
||||||
InputDevice.MotionRange brakeRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_BRAKE);
|
InputDevice.MotionRange brakeRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_BRAKE);
|
||||||
InputDevice.MotionRange gasRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_GAS);
|
InputDevice.MotionRange gasRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_GAS);
|
||||||
|
InputDevice.MotionRange throttleRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_THROTTLE);
|
||||||
if (leftTriggerRange != null && rightTriggerRange != null)
|
if (leftTriggerRange != null && rightTriggerRange != null)
|
||||||
{
|
{
|
||||||
// Some controllers use LTRIGGER and RTRIGGER (like Ouya)
|
// Some controllers use LTRIGGER and RTRIGGER (like Ouya)
|
||||||
@@ -241,6 +245,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
|
context.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
|
||||||
context.rightTriggerAxis = MotionEvent.AXIS_GAS;
|
context.rightTriggerAxis = MotionEvent.AXIS_GAS;
|
||||||
}
|
}
|
||||||
|
else if (brakeRange != null && throttleRange != null)
|
||||||
|
{
|
||||||
|
// Others use THROTTLE and BRAKE (like Xiaomi)
|
||||||
|
context.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
|
||||||
|
context.rightTriggerAxis = MotionEvent.AXIS_THROTTLE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
InputDevice.MotionRange rxRange = getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_RX);
|
||||||
@@ -324,8 +334,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||||
boolean[] hasSelectKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
boolean[] hasSelectKey = dev.hasKeys(KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BACK, 0);
|
||||||
if (hasSelectKey[0] && hasSelectKey[1]) {
|
if (hasSelectKey[0] && hasSelectKey[1]) {
|
||||||
LimeLog.info("Ignoring back button because select is present");
|
// Xiaomi gamepads claim to have both buttons then only send KEYCODE_BACK events
|
||||||
context.ignoreBack = true;
|
if (dev.getVendorId() != 0x2717) {
|
||||||
|
LimeLog.info("Ignoring back button because select is present");
|
||||||
|
context.ignoreBack = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,12 +411,82 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendControllerInputPacket(GenericControllerContext context) {
|
private byte maxByMagnitude(byte a, byte b) {
|
||||||
assignControllerNumberIfNeeded(context);
|
int absA = Math.abs(a);
|
||||||
conn.sendControllerInput(context.controllerNumber, context.inputMap,
|
int absB = Math.abs(b);
|
||||||
context.leftTrigger, context.rightTrigger,
|
if (absA > absB) {
|
||||||
context.leftStickX, context.leftStickY,
|
return a;
|
||||||
context.rightStickX, context.rightStickY);
|
}
|
||||||
|
else {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private short maxByMagnitude(short a, short b) {
|
||||||
|
int absA = Math.abs(a);
|
||||||
|
int absB = Math.abs(b);
|
||||||
|
if (absA > absB) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendControllerInputPacket(GenericControllerContext originalContext) {
|
||||||
|
assignControllerNumberIfNeeded(originalContext);
|
||||||
|
|
||||||
|
// Take the context's controller number and fuse all inputs with the same number
|
||||||
|
short controllerNumber = originalContext.controllerNumber;
|
||||||
|
short inputMap = 0;
|
||||||
|
byte leftTrigger = 0;
|
||||||
|
byte rightTrigger = 0;
|
||||||
|
short leftStickX = 0;
|
||||||
|
short leftStickY = 0;
|
||||||
|
short rightStickX = 0;
|
||||||
|
short rightStickY = 0;
|
||||||
|
|
||||||
|
// In order to properly handle controllers that are split into multiple devices,
|
||||||
|
// we must aggregate all controllers with the same controller number into a single
|
||||||
|
// device before we send it.
|
||||||
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
|
GenericControllerContext context = inputDeviceContexts.valueAt(i);
|
||||||
|
if (context.assignedControllerNumber && context.controllerNumber == controllerNumber) {
|
||||||
|
inputMap |= context.inputMap;
|
||||||
|
leftTrigger |= maxByMagnitude(leftTrigger, context.leftTrigger);
|
||||||
|
rightTrigger |= maxByMagnitude(rightTrigger, context.rightTrigger);
|
||||||
|
leftStickX |= maxByMagnitude(leftStickX, context.leftStickX);
|
||||||
|
leftStickY |= maxByMagnitude(leftStickY, context.leftStickY);
|
||||||
|
rightStickX |= maxByMagnitude(rightStickX, context.rightStickX);
|
||||||
|
rightStickY |= maxByMagnitude(rightStickY, context.rightStickY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < usbDeviceContexts.size(); i++) {
|
||||||
|
GenericControllerContext context = usbDeviceContexts.valueAt(i);
|
||||||
|
if (context.assignedControllerNumber && context.controllerNumber == controllerNumber) {
|
||||||
|
inputMap |= context.inputMap;
|
||||||
|
leftTrigger |= maxByMagnitude(leftTrigger, context.leftTrigger);
|
||||||
|
rightTrigger |= maxByMagnitude(rightTrigger, context.rightTrigger);
|
||||||
|
leftStickX |= maxByMagnitude(leftStickX, context.leftStickX);
|
||||||
|
leftStickY |= maxByMagnitude(leftStickY, context.leftStickY);
|
||||||
|
rightStickX |= maxByMagnitude(rightStickX, context.rightStickX);
|
||||||
|
rightStickY |= maxByMagnitude(rightStickY, context.rightStickY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultContext.controllerNumber == controllerNumber) {
|
||||||
|
inputMap |= defaultContext.inputMap;
|
||||||
|
leftTrigger |= maxByMagnitude(leftTrigger, defaultContext.leftTrigger);
|
||||||
|
rightTrigger |= maxByMagnitude(rightTrigger, defaultContext.rightTrigger);
|
||||||
|
leftStickX |= maxByMagnitude(leftStickX, defaultContext.leftStickX);
|
||||||
|
leftStickY |= maxByMagnitude(leftStickY, defaultContext.leftStickY);
|
||||||
|
rightStickX |= maxByMagnitude(rightStickX, defaultContext.rightStickX);
|
||||||
|
rightStickY |= maxByMagnitude(rightStickY, defaultContext.rightStickY);
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.sendControllerInput(controllerNumber, inputMap,
|
||||||
|
leftTrigger, rightTrigger,
|
||||||
|
leftStickX, leftStickY,
|
||||||
|
rightStickX, rightStickY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a valid keycode, 0 to consume, or -1 to not consume the event
|
// Return a valid keycode, 0 to consume, or -1 to not consume the event
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.limelight.binding.input;
|
package com.limelight.binding.input;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import com.limelight.nvstream.NvConnection;
|
import com.limelight.nvstream.NvConnection;
|
||||||
import com.limelight.nvstream.input.MouseButtonPacket;
|
import com.limelight.nvstream.input.MouseButtonPacket;
|
||||||
|
|
||||||
@@ -17,23 +19,27 @@ public class TouchContext {
|
|||||||
private boolean confirmedDrag;
|
private boolean confirmedDrag;
|
||||||
private Timer dragTimer;
|
private Timer dragTimer;
|
||||||
private double distanceMoved;
|
private double distanceMoved;
|
||||||
|
private double xFactor, yFactor;
|
||||||
|
|
||||||
private final NvConnection conn;
|
private final NvConnection conn;
|
||||||
private final int actionIndex;
|
private final int actionIndex;
|
||||||
private final double xFactor;
|
private final int referenceWidth;
|
||||||
private final double yFactor;
|
private final int referenceHeight;
|
||||||
|
private final View targetView;
|
||||||
|
|
||||||
private static final int TAP_MOVEMENT_THRESHOLD = 20;
|
private static final int TAP_MOVEMENT_THRESHOLD = 20;
|
||||||
private static final int TAP_DISTANCE_THRESHOLD = 25;
|
private static final int TAP_DISTANCE_THRESHOLD = 25;
|
||||||
private static final int TAP_TIME_THRESHOLD = 250;
|
private static final int TAP_TIME_THRESHOLD = 250;
|
||||||
private static final int DRAG_TIME_THRESHOLD = 650;
|
private static final int DRAG_TIME_THRESHOLD = 650;
|
||||||
|
|
||||||
public TouchContext(NvConnection conn, int actionIndex, double xFactor, double yFactor)
|
public TouchContext(NvConnection conn, int actionIndex,
|
||||||
|
int referenceWidth, int referenceHeight, View view)
|
||||||
{
|
{
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.actionIndex = actionIndex;
|
this.actionIndex = actionIndex;
|
||||||
this.xFactor = xFactor;
|
this.referenceWidth = referenceWidth;
|
||||||
this.yFactor = yFactor;
|
this.referenceHeight = referenceHeight;
|
||||||
|
this.targetView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getActionIndex()
|
public int getActionIndex()
|
||||||
@@ -68,6 +74,10 @@ public class TouchContext {
|
|||||||
|
|
||||||
public boolean touchDownEvent(int eventX, int eventY)
|
public boolean touchDownEvent(int eventX, int eventY)
|
||||||
{
|
{
|
||||||
|
// Get the view dimensions to scale inputs on this touch
|
||||||
|
xFactor = referenceWidth / (double)targetView.getWidth();
|
||||||
|
yFactor = referenceHeight / (double)targetView.getHeight();
|
||||||
|
|
||||||
originalTouchX = lastTouchX = eventX;
|
originalTouchX = lastTouchX = eventX;
|
||||||
originalTouchY = lastTouchY = eventY;
|
originalTouchY = lastTouchY = eventY;
|
||||||
originalTouchTime = System.currentTimeMillis();
|
originalTouchTime = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.limelight.binding.input.evdev;
|
package com.limelight.binding.input.evdev;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.app.Activity;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.limelight.LimeLog;
|
import com.limelight.LimeLog;
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ public class EvdevHandler {
|
|||||||
private Process su;
|
private Process su;
|
||||||
private ServerSocket servSock;
|
private ServerSocket servSock;
|
||||||
private Socket evdevSock;
|
private Socket evdevSock;
|
||||||
|
private Activity activity;
|
||||||
|
|
||||||
private static final byte UNGRAB_REQUEST = 1;
|
private static final byte UNGRAB_REQUEST = 1;
|
||||||
private static final byte REGRAB_REQUEST = 2;
|
private static final byte REGRAB_REQUEST = 2;
|
||||||
@@ -49,6 +51,12 @@ public class EvdevHandler {
|
|||||||
try {
|
try {
|
||||||
su = builder.start();
|
su = builder.start();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(activity, "This device is not rooted - Mouse capture is unavailable", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -155,9 +163,10 @@ public class EvdevHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public EvdevHandler(Context context, EvdevListener listener) {
|
public EvdevHandler(Activity activity, EvdevListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.libraryPath = context.getApplicationInfo().nativeLibraryDir;
|
this.activity = activity;
|
||||||
|
this.libraryPath = activity.getApplicationInfo().nativeLibraryDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void regrabAll() {
|
public void regrabAll() {
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ public class MediaCodecHelper {
|
|||||||
// Software decoders that don't support H264 high profile
|
// Software decoders that don't support H264 high profile
|
||||||
blacklistedDecoderPrefixes.add("omx.google");
|
blacklistedDecoderPrefixes.add("omx.google");
|
||||||
blacklistedDecoderPrefixes.add("AVCDecoder");
|
blacklistedDecoderPrefixes.add("AVCDecoder");
|
||||||
|
|
||||||
|
// Without bitstream fixups, we perform horribly on NVIDIA's HEVC
|
||||||
|
// decoder. While not strictly necessary, I'm going to fully blacklist this
|
||||||
|
// one to avoid users getting inaccurate impressions of Tegra X1/Moonlight performance.
|
||||||
|
blacklistedDecoderPrefixes.add("OMX.Nvidia.h265.decode");
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ public class PreferenceConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use small mode on anything smaller than a 7" tablet
|
// Use small mode on anything smaller than a 7" tablet
|
||||||
return context.getResources().getConfiguration().smallestScreenWidthDp < 600;
|
return context.getResources().getConfiguration().screenWidthDp < 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getDefaultBitrate(Context context) {
|
public static int getDefaultBitrate(Context context) {
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.limelight.ui;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
|
||||||
|
public class StreamView extends SurfaceView {
|
||||||
|
private double desiredAspectRatio;
|
||||||
|
|
||||||
|
public void setDesiredAspectRatio(double aspectRatio) {
|
||||||
|
this.desiredAspectRatio = aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
// If no fixed aspect ratio has been provided, simply use the default onMeasure() behavior
|
||||||
|
if (desiredAspectRatio == 0) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on code from: https://www.buzzingandroid.com/2012/11/easy-measuring-of-custom-views-with-specific-aspect-ratio/
|
||||||
|
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
|
||||||
|
int measuredHeight, measuredWidth;
|
||||||
|
if (widthSize > heightSize * desiredAspectRatio) {
|
||||||
|
measuredHeight = heightSize;
|
||||||
|
measuredWidth = (int)(measuredHeight * desiredAspectRatio);
|
||||||
|
} else {
|
||||||
|
measuredWidth = widthSize;
|
||||||
|
measuredHeight = (int)(measuredWidth / desiredAspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasuredDimension(measuredWidth, measuredHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
Submodule app/src/main/jni/jnienet/enet updated: 4f7ef11c23...8b24595dbd.
@@ -1,6 +1,8 @@
|
|||||||
#include "enet/enet.h"
|
#include "enet/enet.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
#define CLIENT_TO_LONG(x) ((intptr_t)(x))
|
#define CLIENT_TO_LONG(x) ((intptr_t)(x))
|
||||||
@@ -15,9 +17,21 @@ Java_com_limelight_nvstream_enet_EnetConnection_initializeEnet(JNIEnv *env, jobj
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_com_limelight_nvstream_enet_EnetConnection_createClient(JNIEnv *env, jobject class) {
|
Java_com_limelight_nvstream_enet_EnetConnection_createClient(JNIEnv *env, jobject class, jstring address) {
|
||||||
|
ENetAddress enetAddress;
|
||||||
|
const char *addrStr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
// Perform a lookup on the address to determine the address family
|
||||||
|
addrStr = (*env)->GetStringUTFChars(env, address, 0);
|
||||||
|
err = enet_address_set_host(&enetAddress, addrStr);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, address, addrStr);
|
||||||
|
if (err < 0) {
|
||||||
|
return CLIENT_TO_LONG(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a client that can use 1 outgoing connection and 1 channel
|
// Create a client that can use 1 outgoing connection and 1 channel
|
||||||
return CLIENT_TO_LONG(enet_host_create(NULL, 1, 1, 0, 0));
|
return CLIENT_TO_LONG(enet_host_create(enetAddress.address.ss_family, NULL, 1, 1, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
@@ -26,12 +40,16 @@ Java_com_limelight_nvstream_enet_EnetConnection_connectToPeer(JNIEnv *env, jobje
|
|||||||
ENetAddress enetAddress;
|
ENetAddress enetAddress;
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
const char *addrStr;
|
const char *addrStr;
|
||||||
|
int err;
|
||||||
|
|
||||||
// Initialize the ENet address
|
// Initialize the ENet address
|
||||||
addrStr = (*env)->GetStringUTFChars(env, address, 0);
|
addrStr = (*env)->GetStringUTFChars(env, address, 0);
|
||||||
enet_address_set_host(&enetAddress, addrStr);
|
err = enet_address_set_host(&enetAddress, addrStr);
|
||||||
enet_address_set_port(&enetAddress, port);
|
enet_address_set_port(&enetAddress, port);
|
||||||
(*env)->ReleaseStringUTFChars(env, address, addrStr);
|
(*env)->ReleaseStringUTFChars(env, address, addrStr);
|
||||||
|
if (err < 0) {
|
||||||
|
return PEER_TO_LONG(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Start the connection
|
// Start the connection
|
||||||
peer = enet_host_connect(LONG_TO_CLIENT(client), &enetAddress, 1, 0);
|
peer = enet_host_connect(LONG_TO_CLIENT(client), &enetAddress, 1, 0);
|
||||||
@@ -99,9 +117,16 @@ Java_com_limelight_nvstream_enet_EnetConnection_writePacket(JNIEnv *env, jobject
|
|||||||
packet = enet_packet_create(dataPtr, length, packetFlags);
|
packet = enet_packet_create(dataPtr, length, packetFlags);
|
||||||
if (packet != NULL) {
|
if (packet != NULL) {
|
||||||
// Send the message to the peer
|
// Send the message to the peer
|
||||||
enet_peer_send(LONG_TO_PEER(peer), 0, packet);
|
if (enet_peer_send(LONG_TO_PEER(peer), 0, packet) < 0) {
|
||||||
enet_host_flush(LONG_TO_CLIENT(client));
|
// This can fail if the peer has been disconnected
|
||||||
ret = JNI_TRUE;
|
enet_packet_destroy(packet);
|
||||||
|
ret = JNI_FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Force the client to send the packet now
|
||||||
|
enet_host_flush(LONG_TO_CLIENT(client));
|
||||||
|
ret = JNI_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret = JNI_FALSE;
|
ret = JNI_FALSE;
|
||||||
@@ -112,12 +137,12 @@ Java_com_limelight_nvstream_enet_EnetConnection_writePacket(JNIEnv *env, jobject
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_limelight_nvstream_enet_EnetConnection_destroyClient(JNIEnv *env, jobject class, jlong client) {
|
Java_com_limelight_nvstream_enet_EnetConnection_destroyClient(JNIEnv *env, jobject class, jlong client) {
|
||||||
enet_host_destroy(LONG_TO_CLIENT(client));
|
enet_host_destroy(LONG_TO_CLIENT(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_limelight_nvstream_enet_EnetConnection_disconnectPeer(JNIEnv *env, jobject class, jlong peer) {
|
Java_com_limelight_nvstream_enet_EnetConnection_disconnectPeer(JNIEnv *env, jobject class, jlong peer) {
|
||||||
enet_peer_disconnect_now(LONG_TO_PEER(peer), 0);
|
enet_peer_disconnect_now(LONG_TO_PEER(peer), 0);
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".Game" >
|
tools:context=".Game" >
|
||||||
|
|
||||||
<SurfaceView
|
<com.limelight.ui.StreamView
|
||||||
android:id="@+id/surfaceView"
|
android:id="@+id/surfaceView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.0.0-beta6'
|
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user