Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1d7f556fd | ||
|
|
1e70e1d329 | ||
|
|
e02a009635 | ||
|
|
bd6ff35603 | ||
|
|
1cb7727dc7 | ||
|
|
0c73e3d0ae | ||
|
|
6371d364e1 | ||
|
|
ded9c9140d | ||
|
|
7c8a108e28 | ||
|
|
2a18ffcdba | ||
|
|
381d0d5e81 | ||
|
|
be126acfd1 | ||
|
|
fc2f5cfe4d | ||
|
|
9878902a89 | ||
|
|
f1230d46f3 | ||
|
|
d8822392f1 | ||
|
|
1d9cf71517 | ||
|
|
2160e87fef | ||
|
|
88249ba8aa | ||
|
|
2856617fb3 | ||
|
|
d822980d5a | ||
|
|
b5ba59b413 | ||
|
|
1148e0163c | ||
|
|
cf36c7adb1 | ||
|
|
eac6998e17 | ||
|
|
17afbffdb5 | ||
|
|
072a439c2d |
No files matched your search
@@ -1,14 +1,14 @@
|
|||||||
#Limelight
|
#Moonlight
|
||||||
|
|
||||||
Limelight is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
|
[Moonlight](http://moonlight-stream.com) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
|
||||||
We reverse engineered the Shield streaming software and created a version that can be run on any Android device.
|
We reverse engineered the Shield streaming software and created a version that can be run on any Android device.
|
||||||
|
|
||||||
Limelight will allow you to stream your full collection of games from your Windows PC to your Android device,
|
Moonlight will allow you to stream your full collection of games from your Windows PC to your Android device,
|
||||||
whether in your own home or over the internet.
|
whether in your own home or over the internet.
|
||||||
|
|
||||||
[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) are also in development.
|
[Moonlight-pc](https://github.com/moonlight-stream/moonlight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/moonlight-stream/moonlight-ios) and [Windows and Windows Phone](https://github.com/moonlight-stream/moonlight-windows) are also in development.
|
||||||
|
|
||||||
Check our [wiki](https://github.com/limelight-stream/limelight-android/wiki) for more detailed information or a troubleshooting guide.
|
Check our [wiki](https://github.com/moonlight-stream/moonlight-android/wiki) for more detailed information or a troubleshooting guide.
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ Check our [wiki](https://github.com/limelight-stream/limelight-android/wiki) for
|
|||||||
|
|
||||||
##Installation
|
##Installation
|
||||||
|
|
||||||
* Download and install Limelight for Android from
|
* Download and install Moonlight for Android from
|
||||||
[Google Play](https://play.google.com/store/apps/details?id=com.limelight)
|
[Google Play](https://play.google.com/store/apps/details?id=com.limelight)
|
||||||
* Download [GeForce Experience](http://www.geforce.com/geforce-experience) and install on your Windows PC
|
* Download [GeForce Experience](http://www.geforce.com/geforce-experience) and install on your Windows PC
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Check our [wiki](https://github.com/limelight-stream/limelight-android/wiki) for
|
|||||||
* Turn on GameStream in the GFE settings
|
* Turn on GameStream in the GFE settings
|
||||||
* If you are connecting from outside the same network, turn on internet
|
* If you are connecting from outside the same network, turn on internet
|
||||||
streaming
|
streaming
|
||||||
* When on the same network as your PC, open Limelight and tap on your PC in the list
|
* When on the same network as your PC, open Moonlight and tap on your PC in the list
|
||||||
* Accept the pairing confirmation on your PC
|
* Accept the pairing confirmation on your PC
|
||||||
* Tap your PC again to view the list of apps to stream
|
* Tap your PC again to view the list of apps to stream
|
||||||
* Play games!
|
* Play games!
|
||||||
@@ -46,8 +46,6 @@ This project is being actively developed at [XDA Developers](http://forum.xda-de
|
|||||||
2. Write code
|
2. Write code
|
||||||
3. Send Pull Requests
|
3. Send Pull Requests
|
||||||
|
|
||||||
Check out our [website](http://limelight-stream.com) for project links and information.
|
|
||||||
|
|
||||||
##Authors
|
##Authors
|
||||||
|
|
||||||
* [Cameron Gutman](https://github.com/cgutman)
|
* [Cameron Gutman](https://github.com/cgutman)
|
||||||
@@ -55,5 +53,5 @@ Check out our [website](http://limelight-stream.com) for project links and infor
|
|||||||
* [Aaron Neyer](https://github.com/Aaronneyer)
|
* [Aaron Neyer](https://github.com/Aaronneyer)
|
||||||
* [Andrew Hennessy](https://github.com/yetanothername)
|
* [Andrew Hennessy](https://github.com/yetanothername)
|
||||||
|
|
||||||
Limelight is the work of students at [Case Western](http://case.edu) and was
|
Moonlight is the work of students at [Case Western](http://case.edu) and was
|
||||||
started as a project at [MHacks](http://mhacks.org).
|
started as a project at [MHacks](http://mhacks.org).
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="limelight-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="moonlight-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="android-gradle" name="Android-Gradle">
|
<facet type="android-gradle" name="Android-Gradle">
|
||||||
<configuration>
|
<configuration>
|
||||||
@@ -12,8 +12,9 @@
|
|||||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||||
<option name="ASSEMBLE_TASK_NAME" value="assembleNonRootDebug" />
|
<option name="ASSEMBLE_TASK_NAME" value="assembleNonRootDebug" />
|
||||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileNonRootDebugSources" />
|
<option name="COMPILE_JAVA_TASK_NAME" value="compileNonRootDebugSources" />
|
||||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleNonRootDebugAndroidTest" />
|
|
||||||
<option name="SOURCE_GEN_TASK_NAME" value="generateNonRootDebugSources" />
|
<option name="SOURCE_GEN_TASK_NAME" value="generateNonRootDebugSources" />
|
||||||
|
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleNonRootDebugAndroidTest" />
|
||||||
|
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileNonRootDebugAndroidTestSources" />
|
||||||
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateNonRootDebugAndroidTestSources" />
|
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateNonRootDebugAndroidTestSources" />
|
||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||||
@@ -114,5 +115,4 @@
|
|||||||
<orderEntry type="library" exported="" name="jcodec-0.1.9" level="project" />
|
<orderEntry type="library" exported="" name="jcodec-0.1.9" level="project" />
|
||||||
<orderEntry type="library" exported="" name="okio-1.2.0" level="project" />
|
<orderEntry type="library" exported="" name="okio-1.2.0" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ android {
|
|||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
|
|
||||||
versionName "3.1.3"
|
versionName "3.1.8"
|
||||||
versionCode = 58
|
versionCode = 63
|
||||||
}
|
}
|
||||||
|
|
||||||
productFlavors {
|
productFlavors {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:theme="@style/AppTheme" >
|
android:theme="@style/AppTheme" >
|
||||||
|
|
||||||
|
<!-- Samsung multi-window support -->
|
||||||
|
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false" />
|
||||||
|
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||||
|
|
||||||
<!-- Launcher for traditional devices -->
|
<!-- Launcher for traditional devices -->
|
||||||
<activity
|
<activity
|
||||||
@@ -24,6 +28,7 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
|
||||||
<category android:name="tv.ouya.intent.category.APP" />
|
<category android:name="tv.ouya.intent.category.APP" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
package com.limelight;
|
package com.limelight;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.limelight.binding.PlatformBinding;
|
|
||||||
import com.limelight.computers.ComputerManagerListener;
|
import com.limelight.computers.ComputerManagerListener;
|
||||||
import com.limelight.computers.ComputerManagerService;
|
import com.limelight.computers.ComputerManagerService;
|
||||||
import com.limelight.grid.AppGridAdapter;
|
import com.limelight.grid.AppGridAdapter;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
import com.limelight.nvstream.http.NvHTTP;
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
import com.limelight.preferences.PreferenceConfiguration;
|
import com.limelight.preferences.PreferenceConfiguration;
|
||||||
@@ -26,10 +21,8 @@ import com.limelight.utils.SpinnerDialog;
|
|||||||
import com.limelight.utils.UiHelper;
|
import com.limelight.utils.UiHelper;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
|||||||
@@ -306,6 +306,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
||||||
addr = computer.remoteIp;
|
addr = computer.remoteIp;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
LimeLog.warning("Unknown reachability - using local IP");
|
||||||
|
addr = computer.localIp;
|
||||||
|
}
|
||||||
|
|
||||||
httpConn = new NvHTTP(addr,
|
httpConn = new NvHTTP(addr,
|
||||||
managerBinder.getUniqueId(),
|
managerBinder.getUniqueId(),
|
||||||
@@ -431,6 +435,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
||||||
addr = computer.remoteIp;
|
addr = computer.remoteIp;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
LimeLog.warning("Unknown reachability - using local IP");
|
||||||
|
addr = computer.localIp;
|
||||||
|
}
|
||||||
|
|
||||||
httpConn = new NvHTTP(addr,
|
httpConn = new NvHTTP(addr,
|
||||||
managerBinder.getUniqueId(),
|
managerBinder.getUniqueId(),
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.limelight.binding.input;
|
package com.limelight.binding.input;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -31,7 +29,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
|
|
||||||
private final Vector2d inputVector = new Vector2d();
|
private final Vector2d inputVector = new Vector2d();
|
||||||
|
|
||||||
private final HashMap<String, ControllerContext> contexts = new HashMap<String, ControllerContext>();
|
private final SparseArray<ControllerContext> contexts = new SparseArray<ControllerContext>();
|
||||||
|
|
||||||
private final NvConnection conn;
|
private final NvConnection conn;
|
||||||
private final double stickDeadzone;
|
private final double stickDeadzone;
|
||||||
@@ -52,8 +50,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
deadzonePercentage = 10;
|
deadzonePercentage = 10;
|
||||||
|
|
||||||
int[] ids = InputDevice.getDeviceIds();
|
int[] ids = InputDevice.getDeviceIds();
|
||||||
for (int i = 0; i < ids.length; i++) {
|
for (int id : ids) {
|
||||||
InputDevice dev = InputDevice.getDevice(ids[i]);
|
InputDevice dev = InputDevice.getDevice(id);
|
||||||
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0 ||
|
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0 ||
|
||||||
(dev.getSources() & InputDevice.SOURCE_GAMEPAD) != 0) {
|
(dev.getSources() & InputDevice.SOURCE_GAMEPAD) != 0) {
|
||||||
// This looks like a gamepad, but we'll check X and Y to be sure
|
// This looks like a gamepad, but we'll check X and Y to be sure
|
||||||
@@ -97,18 +95,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
private short assignNewControllerNumber() {
|
|
||||||
for (short i = 0; i < 4; i++) {
|
|
||||||
if ((currentControllers & (1 << i)) == 0) {
|
|
||||||
// Found an unused controller value
|
|
||||||
currentControllers |= (1 << i);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceAdded(int deviceId) {
|
public void onInputDeviceAdded(int deviceId) {
|
||||||
// Nothing happening here yet
|
// Nothing happening here yet
|
||||||
@@ -116,13 +102,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceRemoved(int deviceId) {
|
public void onInputDeviceRemoved(int deviceId) {
|
||||||
for (Map.Entry<String, ControllerContext> device : contexts.entrySet()) {
|
ControllerContext context = contexts.get(deviceId);
|
||||||
if (device.getValue().id == deviceId) {
|
if (context != null) {
|
||||||
LimeLog.info("Removed controller: "+device.getValue().name);
|
LimeLog.info("Removed controller: "+context.name+" ("+deviceId+")");
|
||||||
releaseControllerNumber(device.getValue().controllerNumber);
|
releaseControllerNumber(context);
|
||||||
contexts.remove(device.getKey());
|
contexts.remove(deviceId);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +117,47 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
onInputDeviceAdded(deviceId);
|
onInputDeviceAdded(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseControllerNumber(int controllerNumber) {
|
private void releaseControllerNumber(ControllerContext context) {
|
||||||
LimeLog.info("Controller number "+controllerNumber+" is now available");
|
if (context.reservedControllerNumber) {
|
||||||
currentControllers &= ~(1 << controllerNumber);
|
LimeLog.info("Controller number "+context.controllerNumber+" is now available");
|
||||||
|
currentControllers &= ~(1 << context.controllerNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called before sending input but after we've determined that this
|
||||||
|
// is definitely a controller (not a keyboard, mouse, or something else)
|
||||||
|
private void assignControllerNumberIfNeeded(ControllerContext context) {
|
||||||
|
if (context.assignedControllerNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LimeLog.info(context.name+" ("+context.id+") needs a controller number assigned");
|
||||||
|
if (context.name != null && context.name.contains("gpio-keys")) {
|
||||||
|
// This is the back button on Shield portable consoles
|
||||||
|
LimeLog.info("Built-in buttons hardcoded as controller 0");
|
||||||
|
context.controllerNumber = 0;
|
||||||
|
}
|
||||||
|
else if (multiControllerEnabled && context.hasJoystickAxes) {
|
||||||
|
context.controllerNumber = 0;
|
||||||
|
|
||||||
|
LimeLog.info("Reserving the next available controller number");
|
||||||
|
for (short i = 0; i < 4; i++) {
|
||||||
|
if ((currentControllers & (1 << i)) == 0) {
|
||||||
|
// Found an unused controller value
|
||||||
|
currentControllers |= (1 << i);
|
||||||
|
context.controllerNumber = i;
|
||||||
|
context.reservedControllerNumber = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LimeLog.info("Not reserving a controller number");
|
||||||
|
context.controllerNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LimeLog.info("Assigned as controller "+context.controllerNumber);
|
||||||
|
context.assignedControllerNumber = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ControllerContext createContextForDevice(InputDevice dev) {
|
private ControllerContext createContextForDevice(InputDevice dev) {
|
||||||
@@ -251,6 +273,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore the back buttonn if a controller has both buttons
|
||||||
|
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);
|
||||||
|
if (hasSelectKey[0] && hasSelectKey[1]) {
|
||||||
|
LimeLog.info("Ignoring back button because select is present");
|
||||||
|
context.ignoreBack = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (devName != null) {
|
if (devName != null) {
|
||||||
// For the Nexus Player (and probably other ATV devices), we should
|
// For the Nexus Player (and probably other ATV devices), we should
|
||||||
// use the back button as start since it doesn't have a start/menu button
|
// use the back button as start since it doesn't have a start/menu button
|
||||||
@@ -274,7 +305,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
else if (devName.contains("Fire TV Remote") || devName.contains("Nexus Remote")) {
|
else if (devName.contains("Fire TV Remote") || devName.contains("Nexus Remote")) {
|
||||||
// It's only a remote if it doesn't any sticks
|
// It's only a remote if it doesn't any sticks
|
||||||
if (!context.hasJoystickAxes) {
|
if (!context.hasJoystickAxes) {
|
||||||
context.isRemote = true;
|
context.ignoreBack = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SHIELD controllers will use small stick deadzones
|
// SHIELD controllers will use small stick deadzones
|
||||||
@@ -282,23 +313,22 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
context.leftStickDeadzoneRadius = 0.07f;
|
context.leftStickDeadzoneRadius = 0.07f;
|
||||||
context.rightStickDeadzoneRadius = 0.07f;
|
context.rightStickDeadzoneRadius = 0.07f;
|
||||||
}
|
}
|
||||||
|
// Samsung's face buttons appear as a non-virtual button so we'll explicitly ignore
|
||||||
|
// back presses on this device
|
||||||
|
else if (devName.equals("sec_touchscreen")) {
|
||||||
|
context.ignoreBack = true;
|
||||||
|
}
|
||||||
|
// The Serval has a couple of unknown buttons that are start and select. It also has
|
||||||
|
// a back button which we want to ignore since there's already a select button.
|
||||||
|
else if (devName.contains("Razer Serval")) {
|
||||||
|
context.isServal = true;
|
||||||
|
context.ignoreBack = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
LimeLog.info("Analog stick deadzone: "+context.leftStickDeadzoneRadius+" "+context.rightStickDeadzoneRadius);
|
||||||
LimeLog.info("Trigger deadzone: "+context.triggerDeadzone);
|
LimeLog.info("Trigger deadzone: "+context.triggerDeadzone);
|
||||||
|
|
||||||
if (devName != null && devName.equals("gpio-keys")) {
|
|
||||||
// This is the back button on Shield portable consoles
|
|
||||||
context.controllerNumber = 0;
|
|
||||||
}
|
|
||||||
else if (multiControllerEnabled && context.hasJoystickAxes) {
|
|
||||||
context.controllerNumber = assignNewControllerNumber();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context.controllerNumber = 0;
|
|
||||||
}
|
|
||||||
LimeLog.info("Assigned as controller "+context.controllerNumber);
|
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,22 +338,21 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
return defaultContext;
|
return defaultContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
String descriptor = dev.getDescriptor();
|
|
||||||
|
|
||||||
// Return the existing context if it exists
|
// Return the existing context if it exists
|
||||||
ControllerContext context = contexts.get(descriptor);
|
ControllerContext context = contexts.get(dev.getId());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise create a new context
|
// Otherwise create a new context
|
||||||
context = createContextForDevice(dev);
|
context = createContextForDevice(dev);
|
||||||
contexts.put(descriptor, context);
|
contexts.put(dev.getId(), context);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendControllerInputPacket(ControllerContext context) {
|
private void sendControllerInputPacket(ControllerContext context) {
|
||||||
|
assignControllerNumberIfNeeded(context);
|
||||||
conn.sendControllerInput(context.controllerNumber, context.inputMap,
|
conn.sendControllerInput(context.controllerNumber, context.inputMap,
|
||||||
context.leftTrigger, context.rightTrigger,
|
context.leftTrigger, context.rightTrigger,
|
||||||
context.leftStickX, context.leftStickY,
|
context.leftStickX, context.leftStickY,
|
||||||
@@ -333,8 +362,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
// 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
|
||||||
// Device MAY BE NULL
|
// Device MAY BE NULL
|
||||||
private int handleRemapping(ControllerContext context, KeyEvent event) {
|
private int handleRemapping(ControllerContext context, KeyEvent event) {
|
||||||
// For remotes, don't capture the back button
|
// Don't capture the back button if configured
|
||||||
if (context.isRemote) {
|
if (context.ignoreBack) {
|
||||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -378,6 +407,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If this is a Serval controller sending an unknown key code, it's probably
|
||||||
|
// the start and select buttons
|
||||||
|
else if (context.isServal && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
|
||||||
|
switch (event.getScanCode()) {
|
||||||
|
case 314:
|
||||||
|
return KeyEvent.KEYCODE_BUTTON_SELECT;
|
||||||
|
case 315:
|
||||||
|
return KeyEvent.KEYCODE_BUTTON_START;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context.hatXAxis != -1 && context.hatYAxis != -1) {
|
if (context.hatXAxis != -1 && context.hatYAxis != -1) {
|
||||||
switch (event.getKeyCode()) {
|
switch (event.getKeyCode()) {
|
||||||
@@ -799,11 +838,14 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
|||||||
|
|
||||||
public boolean isDualShock4;
|
public boolean isDualShock4;
|
||||||
public boolean isXboxController;
|
public boolean isXboxController;
|
||||||
|
public boolean isServal;
|
||||||
public boolean backIsStart;
|
public boolean backIsStart;
|
||||||
public boolean modeIsSelect;
|
public boolean modeIsSelect;
|
||||||
public boolean isRemote;
|
public boolean ignoreBack;
|
||||||
public boolean hasJoystickAxes;
|
public boolean hasJoystickAxes;
|
||||||
|
|
||||||
|
public boolean assignedControllerNumber;
|
||||||
|
public boolean reservedControllerNumber;
|
||||||
public short controllerNumber;
|
public short controllerNumber;
|
||||||
|
|
||||||
public short inputMap = 0x0000;
|
public short inputMap = 0x0000;
|
||||||
|
|||||||
@@ -231,7 +231,8 @@ public class AndroidCpuDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
if (decodeUnit.getDataLength() <= DECODER_BUFFER_SIZE) {
|
if (decodeUnit.getDataLength() <= DECODER_BUFFER_SIZE) {
|
||||||
decoderBuffer.clear();
|
decoderBuffer.clear();
|
||||||
|
|
||||||
for (ByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
|
for (ByteBufferDescriptor bbd = decodeUnit.getBufferHead();
|
||||||
|
bbd != null; bbd = bbd.nextDescriptor) {
|
||||||
decoderBuffer.put(bbd.data, bbd.offset, bbd.length);
|
decoderBuffer.put(bbd.data, bbd.offset, bbd.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +242,8 @@ public class AndroidCpuDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
data = new byte[decodeUnit.getDataLength()+AvcDecoder.getInputPaddingSize()];
|
data = new byte[decodeUnit.getDataLength()+AvcDecoder.getInputPaddingSize()];
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (ByteBufferDescriptor bbd : decodeUnit.getBufferList()) {
|
for (ByteBufferDescriptor bbd = decodeUnit.getBufferHead();
|
||||||
|
bbd != null; bbd = bbd.nextDescriptor) {
|
||||||
System.arraycopy(bbd.data, bbd.offset, data, offset, bbd.length);
|
System.arraycopy(bbd.data, bbd.offset, data, offset, bbd.length);
|
||||||
offset += bbd.length;
|
offset += bbd.length;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,11 +134,14 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf != null || codecFlags != 0) {
|
// Only throw if this happens at the beginning of a stream
|
||||||
throw new RendererException(this, e, buf, codecFlags);
|
if (totalFrames < 60) {
|
||||||
}
|
if (buf != null || codecFlags != 0) {
|
||||||
else {
|
throw new RendererException(this, e, buf, codecFlags);
|
||||||
throw new RendererException(this, e);
|
}
|
||||||
|
else {
|
||||||
|
throw new RendererException(this, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,13 +242,13 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
inputIndex = dequeueInputBuffer(false, false);
|
inputIndex = dequeueInputBuffer(false, false);
|
||||||
du = depacketizer.pollNextDecodeUnit();
|
du = depacketizer.pollNextDecodeUnit();
|
||||||
|
if (du != null) {
|
||||||
|
lastDuDequeueTime = System.currentTimeMillis();
|
||||||
|
notifyDuReceived(du);
|
||||||
|
}
|
||||||
|
|
||||||
// Stop if we can't get a DU or input buffer
|
// Stop if we can't get a DU or input buffer
|
||||||
if (du == null || inputIndex == -1) {
|
if (du == null || inputIndex == -1) {
|
||||||
if (du != null) {
|
|
||||||
lastDuDequeueTime = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +286,7 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
du = depacketizer.pollNextDecodeUnit();
|
du = depacketizer.pollNextDecodeUnit();
|
||||||
if (du != null) {
|
if (du != null) {
|
||||||
lastDuDequeueTime = System.currentTimeMillis();
|
lastDuDequeueTime = System.currentTimeMillis();
|
||||||
|
notifyDuReceived(du);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,14 +425,7 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void submitDecodeUnit(DecodeUnit decodeUnit, ByteBuffer buf, int inputBufferIndex) {
|
private void submitDecodeUnit(DecodeUnit decodeUnit, ByteBuffer buf, int inputBufferIndex) {
|
||||||
long currentTime = System.currentTimeMillis();
|
long timestampUs = System.currentTimeMillis() * 1000;
|
||||||
long delta = currentTime-decodeUnit.getReceiveTimestamp();
|
|
||||||
if (delta >= 0 && delta < 1000) {
|
|
||||||
totalTimeMs += currentTime-decodeUnit.getReceiveTimestamp();
|
|
||||||
totalFrames++;
|
|
||||||
}
|
|
||||||
|
|
||||||
long timestampUs = currentTime * 1000;
|
|
||||||
if (timestampUs <= lastTimestampUs) {
|
if (timestampUs <= lastTimestampUs) {
|
||||||
// We can't submit multiple buffers with the same timestamp
|
// We can't submit multiple buffers with the same timestamp
|
||||||
// so bump it up by one before queuing
|
// so bump it up by one before queuing
|
||||||
@@ -452,7 +449,7 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
boolean needsSpsReplay = false;
|
boolean needsSpsReplay = false;
|
||||||
|
|
||||||
if ((decodeUnitFlags & DecodeUnit.DU_FLAG_CODEC_CONFIG) != 0) {
|
if ((decodeUnitFlags & DecodeUnit.DU_FLAG_CODEC_CONFIG) != 0) {
|
||||||
ByteBufferDescriptor header = decodeUnit.getBufferList().get(0);
|
ByteBufferDescriptor header = decodeUnit.getBufferHead();
|
||||||
if (header.data[header.offset+4] == 0x67) {
|
if (header.data[header.offset+4] == 0x67) {
|
||||||
numSpsIn++;
|
numSpsIn++;
|
||||||
|
|
||||||
@@ -489,19 +486,49 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
LimeLog.info("Patching num_ref_frames in SPS");
|
LimeLog.info("Patching num_ref_frames in SPS");
|
||||||
sps.num_ref_frames = 1;
|
sps.num_ref_frames = 1;
|
||||||
|
|
||||||
|
// GFE 2.5.11 changed the SPS to add additional extensions
|
||||||
|
// Some devices don't like these so we remove them here.
|
||||||
|
sps.vuiParams.video_signal_type_present_flag = false;
|
||||||
|
sps.vuiParams.colour_description_present_flag = false;
|
||||||
|
sps.vuiParams.colour_primaries = 2;
|
||||||
|
sps.vuiParams.transfer_characteristics = 2;
|
||||||
|
sps.vuiParams.matrix_coefficients = 2;
|
||||||
|
sps.vuiParams.chroma_loc_info_present_flag = false;
|
||||||
|
sps.vuiParams.chroma_sample_loc_type_bottom_field = 0;
|
||||||
|
sps.vuiParams.chroma_sample_loc_type_top_field = 0;
|
||||||
|
|
||||||
if (needsSpsBitstreamFixup || isExynos4) {
|
if (needsSpsBitstreamFixup || isExynos4) {
|
||||||
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
||||||
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
||||||
LimeLog.info("Adding bitstream restrictions");
|
|
||||||
|
|
||||||
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
// GFE 2.5.11 started sending bitstream restrictions
|
||||||
sps.vuiParams.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = true;
|
if (sps.vuiParams.bitstreamRestriction == null) {
|
||||||
|
LimeLog.info("Adding bitstream restrictions");
|
||||||
|
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
||||||
|
sps.vuiParams.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = true;
|
||||||
|
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_horizontal = 16;
|
||||||
|
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_vertical = 16;
|
||||||
|
sps.vuiParams.bitstreamRestriction.num_reorder_frames = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LimeLog.info("Patching bitstream restrictions");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some devices throw errors if max_dec_frame_buffering < num_ref_frames
|
||||||
|
sps.vuiParams.bitstreamRestriction.max_dec_frame_buffering = sps.num_ref_frames;
|
||||||
|
|
||||||
|
// These values are the defaults for the fields, but they are more aggressive
|
||||||
|
// than what GFE sends in 2.5.11, but it doesn't seem to cause picture problems.
|
||||||
sps.vuiParams.bitstreamRestriction.max_bytes_per_pic_denom = 2;
|
sps.vuiParams.bitstreamRestriction.max_bytes_per_pic_denom = 2;
|
||||||
sps.vuiParams.bitstreamRestriction.max_bits_per_mb_denom = 1;
|
sps.vuiParams.bitstreamRestriction.max_bits_per_mb_denom = 1;
|
||||||
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_horizontal = 16;
|
|
||||||
sps.vuiParams.bitstreamRestriction.log2_max_mv_length_vertical = 16;
|
// log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more
|
||||||
sps.vuiParams.bitstreamRestriction.num_reorder_frames = 0;
|
// conservative values by GFE 2.5.11. We'll let those values stand.
|
||||||
sps.vuiParams.bitstreamRestriction.max_dec_frame_buffering = 1;
|
}
|
||||||
|
else {
|
||||||
|
// Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11
|
||||||
|
// will continue to not receive them now
|
||||||
|
sps.vuiParams.bitstreamRestriction = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we need to hack this SPS to say we're baseline, do so now
|
// If we need to hack this SPS to say we're baseline, do so now
|
||||||
@@ -537,8 +564,8 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy data from our buffer list into the input buffer
|
// Copy data from our buffer list into the input buffer
|
||||||
for (ByteBufferDescriptor desc : decodeUnit.getBufferList())
|
for (ByteBufferDescriptor desc = decodeUnit.getBufferHead();
|
||||||
{
|
desc != null; desc = desc.nextDescriptor) {
|
||||||
buf.put(desc.data, desc.offset, desc.length);
|
buf.put(desc.data, desc.offset, desc.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,10 +641,21 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
|||||||
return decoderName;
|
return decoderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyDuReceived(DecodeUnit du) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long delta = currentTime-du.getReceiveTimestamp();
|
||||||
|
if (delta >= 0 && delta < 1000) {
|
||||||
|
totalTimeMs += currentTime-du.getReceiveTimestamp();
|
||||||
|
totalFrames++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void directSubmitDecodeUnit(DecodeUnit du) {
|
public void directSubmitDecodeUnit(DecodeUnit du) {
|
||||||
int inputIndex;
|
int inputIndex;
|
||||||
|
|
||||||
|
notifyDuReceived(du);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
inputIndex = dequeueInputBuffer(true, true);
|
inputIndex = dequeueInputBuffer(true, true);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public class MediaCodecHelper {
|
|||||||
directSubmitPrefixes.add("omx.intel");
|
directSubmitPrefixes.add("omx.intel");
|
||||||
directSubmitPrefixes.add("omx.brcm");
|
directSubmitPrefixes.add("omx.brcm");
|
||||||
directSubmitPrefixes.add("omx.TI");
|
directSubmitPrefixes.add("omx.TI");
|
||||||
|
directSubmitPrefixes.add("omx.arc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public class ComputerManagerService extends Service {
|
|||||||
if (!pollComputer(details)) {
|
if (!pollComputer(details)) {
|
||||||
if (!newPc && offlineCount < OFFLINE_POLL_TRIES) {
|
if (!newPc && offlineCount < OFFLINE_POLL_TRIES) {
|
||||||
// Return without calling the listener
|
// Return without calling the listener
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +393,7 @@ public class ComputerManagerService extends Service {
|
|||||||
private boolean fastPollIp(InetAddress addr) {
|
private boolean fastPollIp(InetAddress addr) {
|
||||||
Socket s = new Socket();
|
Socket s = new Socket();
|
||||||
try {
|
try {
|
||||||
s.connect(new InetSocketAddress(addr, NvHTTP.PORT), FAST_POLL_TIMEOUT);
|
s.connect(new InetSocketAddress(addr, NvHTTP.HTTPS_PORT), FAST_POLL_TIMEOUT);
|
||||||
s.close();
|
s.close();
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -638,7 +639,7 @@ public class ComputerManagerService extends Service {
|
|||||||
if (cacheOut != null) {
|
if (cacheOut != null) {
|
||||||
cacheOut.close();
|
cacheOut.close();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {}
|
} catch (IOException ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the computer
|
// Update the computer
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
|||||||
|
|
||||||
private final CachedAppAssetLoader loader;
|
private final CachedAppAssetLoader loader;
|
||||||
|
|
||||||
public AppGridAdapter(Activity activity, boolean listMode, boolean small, ComputerDetails computer, String uniqueId) throws KeyManagementException, NoSuchAlgorithmException {
|
public AppGridAdapter(Activity activity, boolean listMode, boolean small, ComputerDetails computer, String uniqueId) {
|
||||||
super(activity, listMode ? R.layout.simple_row : (small ? R.layout.app_grid_item_small : R.layout.app_grid_item), R.drawable.image_loading);
|
super(activity, listMode ? R.layout.simple_row : (small ? R.layout.app_grid_item_small : R.layout.app_grid_item), R.drawable.image_loading);
|
||||||
|
|
||||||
int dpi = activity.getResources().getDisplayMetrics().densityDpi;
|
int dpi = activity.getResources().getDisplayMetrics().densityDpi;
|
||||||
@@ -40,7 +40,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
|||||||
dp = LARGE_WIDTH_DP;
|
dp = LARGE_WIDTH_DP;
|
||||||
}
|
}
|
||||||
|
|
||||||
double scalingDivisor = ART_WIDTH_PX / (dp * (dpi / 160));
|
double scalingDivisor = ART_WIDTH_PX / (dp * (dpi / 160.0));
|
||||||
if (scalingDivisor < 1.0) {
|
if (scalingDivisor < 1.0) {
|
||||||
// We don't want to make them bigger before draw-time
|
// We don't want to make them bigger before draw-time
|
||||||
scalingDivisor = 1.0;
|
scalingDivisor = 1.0;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.widget.ImageView;
|
|||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
import com.limelight.nvstream.http.NvApp;
|
import com.limelight.nvstream.http.NvApp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
@@ -97,6 +98,11 @@ public class CachedAppAssetLoader {
|
|||||||
// Write the stream straight to disk
|
// Write the stream straight to disk
|
||||||
diskLoader.populateCacheWithStream(tuple, in);
|
diskLoader.populateCacheWithStream(tuple, in);
|
||||||
|
|
||||||
|
// Close the network input stream
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
|
||||||
// If there's a task associated with this load, we should return the bitmap
|
// If there's a task associated with this load, we should return the bitmap
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
return diskLoader.loadBitmapFromCache(tuple, (int) scalingDivider);
|
return diskLoader.loadBitmapFromCache(tuple, (int) scalingDivider);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class NetworkAssetLoader {
|
|||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
in = http.getBoxArt(tuple.app);
|
in = http.getBoxArt(tuple.app);
|
||||||
} catch (IOException e) {}
|
} catch (IOException ignored) {}
|
||||||
|
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
LimeLog.info("Network asset load complete: " + tuple);
|
LimeLog.info("Network asset load complete: " + tuple);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.limelight.preferences;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
public class PreferenceConfiguration {
|
public class PreferenceConfiguration {
|
||||||
@@ -69,9 +70,18 @@ public class PreferenceConfiguration {
|
|||||||
|
|
||||||
public static boolean getDefaultSmallMode(Context context) {
|
public static boolean getDefaultSmallMode(Context context) {
|
||||||
PackageManager manager = context.getPackageManager();
|
PackageManager manager = context.getPackageManager();
|
||||||
if (manager != null && manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
|
if (manager != null) {
|
||||||
// TVs shouldn't use small mode by default
|
// TVs shouldn't use small mode by default
|
||||||
return false;
|
if (manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API 21 uses LEANBACK instead of TELEVISION
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||||
|
if (manager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use small mode on anything smaller than a 7" tablet
|
// Use small mode on anything smaller than a 7" tablet
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public class CacheHelper {
|
|||||||
sb.append(buf, 0, bytesRead);
|
sb.append(buf, 0, bytesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 65 KiB |
@@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
<string name="category_ui_settings">Impostazioni Interfaccia</string>
|
<string name="category_ui_settings">Impostazioni Interfaccia</string>
|
||||||
<string name="title_language_list">Lingua</string>
|
<string name="title_language_list">Lingua</string>
|
||||||
<string name="summary_language_list">Lingua da usare in Limelight</string>
|
<string name="summary_language_list">Lingua da usare in Moonlight</string>
|
||||||
<string name="title_checkbox_list_mode">Usa lista invece della griglia</string>
|
<string name="title_checkbox_list_mode">Usa lista invece della griglia</string>
|
||||||
<string name="summary_checkbox_list_mode">Visualizza applicazioni e computers in una lista invece di una griglia</string>
|
<string name="summary_checkbox_list_mode">Visualizza applicazioni e computers in una lista invece di una griglia</string>
|
||||||
<string name="title_checkbox_small_icon_mode">Usa icone piccole</string>
|
<string name="title_checkbox_small_icon_mode">Usa icone piccole</string>
|
||||||
|
|||||||
@@ -44,9 +44,9 @@
|
|||||||
<string name="conn_establishing_title">Establishing Connection</string>
|
<string name="conn_establishing_title">Establishing Connection</string>
|
||||||
<string name="conn_establishing_msg">Starting connection</string>
|
<string name="conn_establishing_msg">Starting connection</string>
|
||||||
<string name="conn_metered">Warning: Your active network connection is metered!</string>
|
<string name="conn_metered">Warning: Your active network connection is metered!</string>
|
||||||
<string name="conn_client_latency">Average client-side frame latency:</string>
|
<string name="conn_client_latency">Average frame decoding latency:</string>
|
||||||
<string name="conn_client_latency_hw">hardware decoder latency:</string>
|
<string name="conn_client_latency_hw">hardware decoder latency:</string>
|
||||||
<string name="conn_hardware_latency">Average hardware decoder latency:</string>
|
<string name="conn_hardware_latency">Average hardware decoding latency:</string>
|
||||||
<string name="conn_starting">Starting</string>
|
<string name="conn_starting">Starting</string>
|
||||||
<string name="conn_error_title">Connection Error</string>
|
<string name="conn_error_title">Connection Error</string>
|
||||||
<string name="conn_error_msg">Failed to start</string>
|
<string name="conn_error_msg">Failed to start</string>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
<string name="category_ui_settings">UI Settings</string>
|
<string name="category_ui_settings">UI Settings</string>
|
||||||
<string name="title_language_list">Language</string>
|
<string name="title_language_list">Language</string>
|
||||||
<string name="summary_language_list">Language to use for Limelight</string>
|
<string name="summary_language_list">Language to use for Moonlight</string>
|
||||||
<string name="title_checkbox_list_mode">Use lists instead of grids</string>
|
<string name="title_checkbox_list_mode">Use lists instead of grids</string>
|
||||||
<string name="summary_checkbox_list_mode">Display apps and PCs in lists instead of grids</string>
|
<string name="summary_checkbox_list_mode">Display apps and PCs in lists instead of grids</string>
|
||||||
<string name="title_checkbox_small_icon_mode">Use small icons</string>
|
<string name="title_checkbox_small_icon_mode">Use small icons</string>
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<!-- Non-root application name -->
|
<!-- Non-root application name -->
|
||||||
<application android:label="Limelight" />
|
<application android:label="Moonlight" />
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -5,5 +5,5 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||||
|
|
||||||
<!-- Root application name -->
|
<!-- Root application name -->
|
||||||
<application android:label="Limelight (Root)" />
|
<application android:label="Moonlight (Root)" />
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:1.1.0'
|
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
<module external.linked.project.id="moonlight-android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="java-gradle" name="Java-Gradle">
|
<facet type="java-gradle" name="Java-Gradle">
|
||||||
<configuration>
|
<configuration>
|
||||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||||
|
<option name="BUILDABLE" value="false" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
</component>
|
</component>
|
||||||
@@ -15,5 +16,4 @@
|
|||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||