Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1e135db4d | |||
| 61a17afe69 | |||
| 47fd691884 | |||
| 0d171c6b28 | |||
| f0c69d08b8 | |||
| 629bf5766d | |||
| 233bceeece | |||
| 6660ea7d91 | |||
| 4864b2ca45 | |||
| 92097b318d | |||
| 997898c99d | |||
| 1174e03885 | |||
| ff0f54d541 | |||
| 814964a100 | |||
| 7e154292a9 | |||
| 0f9cba1053 | |||
| a4e134589d | |||
| cd80a94f28 | |||
| 57c645a291 |
+2
-2
@@ -8,8 +8,8 @@ android {
|
|||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
|
|
||||||
versionName "6.1"
|
versionName "6.2"
|
||||||
versionCode = 182
|
versionCode = 186
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "root"
|
flavorDimensions "root"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.limelight;
|
package com.limelight;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import com.limelight.computers.ComputerManagerListener;
|
import com.limelight.computers.ComputerManagerListener;
|
||||||
import com.limelight.computers.ComputerManagerService;
|
import com.limelight.computers.ComputerManagerService;
|
||||||
@@ -28,7 +28,6 @@ import android.content.Intent;
|
|||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -45,6 +44,8 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
public class AppView extends Activity implements AdapterFragmentCallbacks {
|
public class AppView extends Activity implements AdapterFragmentCallbacks {
|
||||||
private AppGridAdapter appGridAdapter;
|
private AppGridAdapter appGridAdapter;
|
||||||
private String uuidString;
|
private String uuidString;
|
||||||
@@ -82,7 +83,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
localBinder.waitForReady();
|
localBinder.waitForReady();
|
||||||
|
|
||||||
// Get the computer object
|
// Get the computer object
|
||||||
computer = localBinder.getComputer(UUID.fromString(uuidString));
|
computer = localBinder.getComputer(uuidString);
|
||||||
if (computer == null) {
|
if (computer == null) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -156,7 +157,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't care about other computers
|
// Don't care about other computers
|
||||||
if (!details.uuid.toString().equalsIgnoreCase(uuidString)) {
|
if (!details.uuid.equalsIgnoreCase(uuidString)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Disable shortcuts referencing this PC for now
|
// Disable shortcuts referencing this PC for now
|
||||||
shortcutHelper.disableShortcut(details.uuid.toString(),
|
shortcutHelper.disableShortcut(details.uuid,
|
||||||
getResources().getString(R.string.scut_not_paired));
|
getResources().getString(R.string.scut_not_paired));
|
||||||
|
|
||||||
// Display a toast to the user and quit the activity
|
// Display a toast to the user and quit the activity
|
||||||
@@ -216,7 +217,9 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
blockingLoadSpinner.dismiss();
|
blockingLoadSpinner.dismiss();
|
||||||
blockingLoadSpinner = null;
|
blockingLoadSpinner = null;
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {}
|
} catch (XmlPullParserException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -280,7 +283,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
List<NvApp> applist = NvHTTP.getAppListByReader(new StringReader(lastRawApplist));
|
List<NvApp> applist = NvHTTP.getAppListByReader(new StringReader(lastRawApplist));
|
||||||
updateUiWithAppList(applist);
|
updateUiWithAppList(applist);
|
||||||
LimeLog.info("Loaded applist from cache");
|
LimeLog.info("Loaded applist from cache");
|
||||||
} catch (Exception e) {
|
} catch (IOException | XmlPullParserException e) {
|
||||||
if (lastRawApplist != null) {
|
if (lastRawApplist != null) {
|
||||||
LimeLog.warning("Saved applist corrupted: "+lastRawApplist);
|
LimeLog.warning("Saved applist corrupted: "+lastRawApplist);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -908,7 +908,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, getModifierState(event));
|
byte modifiers = getModifierState(event);
|
||||||
|
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
|
||||||
|
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
|
||||||
|
conn.sendKeyboardInput((short) 0x8010, KeyboardPacket.KEY_DOWN, modifiers);
|
||||||
|
}
|
||||||
|
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -959,7 +964,14 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, getModifierState(event));
|
byte modifiers = getModifierState(event);
|
||||||
|
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
|
||||||
|
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
|
||||||
|
}
|
||||||
|
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, modifiers);
|
||||||
|
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
|
||||||
|
conn.sendKeyboardInput((short) 0x8010, KeyboardPacket.KEY_UP, getModifierState(event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ import android.widget.RelativeLayout;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.EGLConfig;
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
@@ -420,7 +422,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
message = getResources().getString(R.string.error_unknown_host);
|
message = getResources().getString(R.string.error_unknown_host);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
message = getResources().getString(R.string.error_404);
|
message = getResources().getString(R.string.error_404);
|
||||||
} catch (Exception e) {
|
} catch (XmlPullParserException | IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
message = e.getMessage();
|
message = e.getMessage();
|
||||||
}
|
}
|
||||||
@@ -521,8 +523,9 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
message = getResources().getString(R.string.error_unknown_host);
|
message = getResources().getString(R.string.error_unknown_host);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
message = getResources().getString(R.string.error_404);
|
message = getResources().getString(R.string.error_404);
|
||||||
} catch (Exception e) {
|
} catch (XmlPullParserException | IOException e) {
|
||||||
message = e.getMessage();
|
message = e.getMessage();
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String toastMessage = message;
|
final String toastMessage = message;
|
||||||
@@ -548,7 +551,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
Intent i = new Intent(this, AppView.class);
|
Intent i = new Intent(this, AppView.class);
|
||||||
i.putExtra(AppView.NAME_EXTRA, computer.name);
|
i.putExtra(AppView.NAME_EXTRA, computer.name);
|
||||||
i.putExtra(AppView.UUID_EXTRA, computer.uuid.toString());
|
i.putExtra(AppView.UUID_EXTRA, computer.uuid);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,7 +634,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
if (details.equals(computer.details)) {
|
if (details.equals(computer.details)) {
|
||||||
// Disable or delete shortcuts referencing this PC
|
// Disable or delete shortcuts referencing this PC
|
||||||
shortcutHelper.disableShortcut(details.uuid.toString(),
|
shortcutHelper.disableShortcut(details.uuid,
|
||||||
getResources().getString(R.string.scut_deleted_pc));
|
getResources().getString(R.string.scut_deleted_pc));
|
||||||
|
|
||||||
pcGridAdapter.removeComputer(computer);
|
pcGridAdapter.removeComputer(computer);
|
||||||
@@ -662,7 +665,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
// Add a launcher shortcut for this PC
|
// Add a launcher shortcut for this PC
|
||||||
if (details.pairState == PairState.PAIRED) {
|
if (details.pairState == PairState.PAIRED) {
|
||||||
shortcutHelper.createAppViewShortcut(details.uuid.toString(), details, false);
|
shortcutHelper.createAppViewShortcut(details.uuid, details, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingEntry != null) {
|
if (existingEntry != null) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
managerBinder = localBinder;
|
managerBinder = localBinder;
|
||||||
|
|
||||||
// Get the computer object
|
// Get the computer object
|
||||||
computer = managerBinder.getComputer(UUID.fromString(uuidString));
|
computer = managerBinder.getComputer(uuidString);
|
||||||
|
|
||||||
if (computer == null) {
|
if (computer == null) {
|
||||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
@@ -77,7 +77,7 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void notifyComputerUpdated(final ComputerDetails details) {
|
public void notifyComputerUpdated(final ComputerDetails details) {
|
||||||
// Don't care about other computers
|
// Don't care about other computers
|
||||||
if (!details.uuid.toString().equalsIgnoreCase(uuidString)) {
|
if (!details.uuid.equalsIgnoreCase(uuidString)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +200,14 @@ public class ShortcutTrampoline extends Activity {
|
|||||||
|
|
||||||
protected boolean validateInput() {
|
protected boolean validateInput() {
|
||||||
// Validate UUID
|
// Validate UUID
|
||||||
|
if (uuidString == null) {
|
||||||
|
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||||
|
getResources().getString(R.string.conn_error_title),
|
||||||
|
getResources().getString(R.string.scut_invalid_uuid),
|
||||||
|
true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UUID.fromString(uuidString);
|
UUID.fromString(uuidString);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import java.security.KeyFactory;
|
|||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
@@ -155,7 +154,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Nothing should go wrong here
|
// Nothing should go wrong here
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return false;
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
LimeLog.info("Generated a new key pair");
|
LimeLog.info("Generated a new key pair");
|
||||||
|
|||||||
@@ -48,6 +48,20 @@ public class KeyboardTranslator {
|
|||||||
public static final int VK_QUOTE = 222;
|
public static final int VK_QUOTE = 222;
|
||||||
public static final int VK_PAUSE = 19;
|
public static final int VK_PAUSE = 19;
|
||||||
|
|
||||||
|
public static boolean needsShift(int keycode) {
|
||||||
|
switch (keycode)
|
||||||
|
{
|
||||||
|
case KeyEvent.KEYCODE_AT:
|
||||||
|
case KeyEvent.KEYCODE_POUND:
|
||||||
|
case KeyEvent.KEYCODE_PLUS:
|
||||||
|
case KeyEvent.KEYCODE_STAR:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the given keycode and returns the GFE keycode
|
* Translates the given keycode and returns the GFE keycode
|
||||||
* @param keycode the code to be translated
|
* @param keycode the code to be translated
|
||||||
@@ -117,6 +131,7 @@ public class KeyboardTranslator {
|
|||||||
translated = 0x0d;
|
translated = 0x0d;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KeyEvent.KEYCODE_PLUS:
|
||||||
case KeyEvent.KEYCODE_EQUALS:
|
case KeyEvent.KEYCODE_EQUALS:
|
||||||
translated = 0xbb;
|
translated = 0xbb;
|
||||||
break;
|
break;
|
||||||
@@ -258,6 +273,18 @@ public class KeyboardTranslator {
|
|||||||
translated = 0x6E;
|
translated = 0x6E;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KeyEvent.KEYCODE_AT:
|
||||||
|
translated = 2 + VK_0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyEvent.KEYCODE_POUND:
|
||||||
|
translated = 3 + VK_0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyEvent.KEYCODE_STAR:
|
||||||
|
translated = 8 + VK_0;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
System.out.println("No key for "+keycode);
|
System.out.println("No key for "+keycode);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class Xbox360Controller extends AbstractXboxController {
|
|||||||
private static final int XB360_IFACE_PROTOCOL = 1; // Wired only
|
private static final int XB360_IFACE_PROTOCOL = 1; // Wired only
|
||||||
|
|
||||||
private static final int[] SUPPORTED_VENDORS = {
|
private static final int[] SUPPORTED_VENDORS = {
|
||||||
|
0x0079, // GPD Win 2
|
||||||
0x044f, // Thrustmaster
|
0x044f, // Thrustmaster
|
||||||
0x045e, // Microsoft
|
0x045e, // Microsoft
|
||||||
0x046d, // Logitech
|
0x046d, // Logitech
|
||||||
@@ -23,6 +24,7 @@ public class Xbox360Controller extends AbstractXboxController {
|
|||||||
0x07ff, // Mad Catz
|
0x07ff, // Mad Catz
|
||||||
0x0e6f, // Unknown
|
0x0e6f, // Unknown
|
||||||
0x0f0d, // Hori
|
0x0f0d, // Hori
|
||||||
|
0x1038, // SteelSeries
|
||||||
0x11c9, // Nacon
|
0x11c9, // Nacon
|
||||||
0x12ab, // Unknown
|
0x12ab, // Unknown
|
||||||
0x1430, // RedOctane
|
0x1430, // RedOctane
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.limelight.LimeLog;
|
|||||||
import com.limelight.nvstream.input.ControllerPacket;
|
import com.limelight.nvstream.input.ControllerPacket;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class XboxOneController extends AbstractXboxController {
|
public class XboxOneController extends AbstractXboxController {
|
||||||
|
|
||||||
@@ -23,8 +24,30 @@ public class XboxOneController extends AbstractXboxController {
|
|||||||
0x24c6, // PowerA
|
0x24c6, // PowerA
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: odata_serial
|
private static final byte[] FW2015_INIT = {0x05, 0x20, 0x00, 0x01, 0x00};
|
||||||
private static final byte[] XB1_INIT_DATA = {0x05, 0x20, 0x00, 0x01, 0x00};
|
private static final byte[] HORI_INIT = {0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
|
||||||
|
0x00, 0x00, 0x00, (byte)0x80, 0x00};
|
||||||
|
private static final byte[] PDP_INIT1 = {0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14};
|
||||||
|
private static final byte[] PDP_INIT2 = {0x06, 0x20, 0x00, 0x02, 0x01, 0x00};
|
||||||
|
private static final byte[] RUMBLE_INIT1 = {0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
||||||
|
0x1D, 0x1D, (byte)0xFF, 0x00, 0x00};
|
||||||
|
private static final byte[] RUMBLE_INIT2 = {0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
private static InitPacket[] INIT_PKTS = {
|
||||||
|
new InitPacket(0x0e6f, 0x0165, HORI_INIT),
|
||||||
|
new InitPacket(0x0f0d, 0x0067, HORI_INIT),
|
||||||
|
new InitPacket(0x0000, 0x0000, FW2015_INIT),
|
||||||
|
new InitPacket(0x0e6f, 0x0000, PDP_INIT1),
|
||||||
|
new InitPacket(0x0e6f, 0x0000, PDP_INIT2),
|
||||||
|
new InitPacket(0x24c6, 0x541a, RUMBLE_INIT1),
|
||||||
|
new InitPacket(0x24c6, 0x542a, RUMBLE_INIT1),
|
||||||
|
new InitPacket(0x24c6, 0x543a, RUMBLE_INIT1),
|
||||||
|
new InitPacket(0x24c6, 0x541a, RUMBLE_INIT2),
|
||||||
|
new InitPacket(0x24c6, 0x542a, RUMBLE_INIT2),
|
||||||
|
new InitPacket(0x24c6, 0x543a, RUMBLE_INIT2),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
||||||
super(device, connection, deviceId, listener);
|
super(device, connection, deviceId, listener);
|
||||||
@@ -111,13 +134,43 @@ public class XboxOneController extends AbstractXboxController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doInit() {
|
protected boolean doInit() {
|
||||||
// Send the initialization packet
|
byte seqNum = 0;
|
||||||
int res = connection.bulkTransfer(outEndpt, XB1_INIT_DATA, XB1_INIT_DATA.length, 3000);
|
|
||||||
if (res != XB1_INIT_DATA.length) {
|
// Send all applicable init packets
|
||||||
LimeLog.warning("Initialization transfer failed: "+res);
|
for (InitPacket pkt : INIT_PKTS) {
|
||||||
return false;
|
if (pkt.vendorId != 0 && device.getVendorId() != pkt.vendorId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt.productId != 0 && device.getProductId() != pkt.productId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = Arrays.copyOf(pkt.data, pkt.data.length);
|
||||||
|
|
||||||
|
// Populate sequence number
|
||||||
|
data[2] = seqNum++;
|
||||||
|
|
||||||
|
// Send the initialization packet
|
||||||
|
int res = connection.bulkTransfer(outEndpt, data, data.length, 3000);
|
||||||
|
if (res != data.length) {
|
||||||
|
LimeLog.warning("Initialization transfer failed: "+res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class InitPacket {
|
||||||
|
final int vendorId;
|
||||||
|
final int productId;
|
||||||
|
final byte[] data;
|
||||||
|
|
||||||
|
InitPacket(int vendorId, int productId, byte[] data) {
|
||||||
|
this.vendorId = vendorId;
|
||||||
|
this.productId = productId;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-19
@@ -167,26 +167,22 @@ public class VirtualController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendControllerInputContext() {
|
void sendControllerInputContext() {
|
||||||
try {
|
_DBG("INPUT_MAP + " + inputContext.inputMap);
|
||||||
_DBG("INPUT_MAP + " + inputContext.inputMap);
|
_DBG("LEFT_TRIGGER " + inputContext.leftTrigger);
|
||||||
_DBG("LEFT_TRIGGER " + inputContext.leftTrigger);
|
_DBG("RIGHT_TRIGGER " + inputContext.rightTrigger);
|
||||||
_DBG("RIGHT_TRIGGER " + inputContext.rightTrigger);
|
_DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY);
|
||||||
_DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY);
|
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
|
||||||
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
|
|
||||||
|
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.sendControllerInput(
|
connection.sendControllerInput(
|
||||||
inputContext.inputMap,
|
inputContext.inputMap,
|
||||||
inputContext.leftTrigger,
|
inputContext.leftTrigger,
|
||||||
inputContext.rightTrigger,
|
inputContext.rightTrigger,
|
||||||
inputContext.leftStickX,
|
inputContext.leftStickX,
|
||||||
inputContext.leftStickY,
|
inputContext.leftStickY,
|
||||||
inputContext.rightStickX,
|
inputContext.rightStickX,
|
||||||
inputContext.rightStickY
|
inputContext.rightStickY
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-46
@@ -166,58 +166,54 @@ public abstract class VirtualControllerElement extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void showConfigurationDialog() {
|
protected void showConfigurationDialog() {
|
||||||
try {
|
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext());
|
||||||
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext());
|
|
||||||
|
|
||||||
alertBuilder.setTitle("Configuration");
|
alertBuilder.setTitle("Configuration");
|
||||||
|
|
||||||
CharSequence functions[] = new CharSequence[]{
|
CharSequence functions[] = new CharSequence[]{
|
||||||
"Move",
|
"Move",
|
||||||
"Resize",
|
"Resize",
|
||||||
/*election
|
/*election
|
||||||
"Set n
|
"Set n
|
||||||
Disable color sormal color",
|
Disable color sormal color",
|
||||||
"Set pressed color",
|
"Set pressed color",
|
||||||
|
*/
|
||||||
|
"Cancel"
|
||||||
|
};
|
||||||
|
|
||||||
|
alertBuilder.setItems(functions, new DialogInterface.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
switch (which) {
|
||||||
|
case 0: { // move
|
||||||
|
actionEnableMove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: { // resize
|
||||||
|
actionEnableResize();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
case 2: { // set default color
|
||||||
|
actionShowNormalColorChooser();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: { // set pressed color
|
||||||
|
actionShowPressedColorChooser();
|
||||||
|
break;
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
"Cancel"
|
default: { // cancel
|
||||||
};
|
actionCancel();
|
||||||
|
|
||||||
alertBuilder.setItems(functions, new DialogInterface.OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
switch (which) {
|
|
||||||
case 0: { // move
|
|
||||||
actionEnableMove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: { // resize
|
|
||||||
actionEnableResize();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
case 2: { // set default color
|
|
||||||
actionShowNormalColorChooser();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: { // set pressed color
|
|
||||||
actionShowPressedColorChooser();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
default: { // cancel
|
|
||||||
actionCancel();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
AlertDialog alert = alertBuilder.create();
|
});
|
||||||
// show menu
|
AlertDialog alert = alertBuilder.create();
|
||||||
alert.show();
|
// show menu
|
||||||
} catch (Exception e) {
|
alert.show();
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.limelight.computers;
|
package com.limelight.computers;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
@@ -9,9 +8,7 @@ import java.security.cert.X509Certificate;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import com.limelight.LimeLog;
|
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
@@ -79,7 +76,7 @@ public class ComputerDatabaseManager {
|
|||||||
|
|
||||||
public boolean updateComputer(ComputerDetails details) {
|
public boolean updateComputer(ComputerDetails details) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COMPUTER_UUID_COLUMN_NAME, details.uuid.toString());
|
values.put(COMPUTER_UUID_COLUMN_NAME, details.uuid);
|
||||||
values.put(COMPUTER_NAME_COLUMN_NAME, details.name);
|
values.put(COMPUTER_NAME_COLUMN_NAME, details.name);
|
||||||
values.put(LOCAL_ADDRESS_COLUMN_NAME, details.localAddress);
|
values.put(LOCAL_ADDRESS_COLUMN_NAME, details.localAddress);
|
||||||
values.put(REMOTE_ADDRESS_COLUMN_NAME, details.remoteAddress);
|
values.put(REMOTE_ADDRESS_COLUMN_NAME, details.remoteAddress);
|
||||||
@@ -102,14 +99,7 @@ public class ComputerDatabaseManager {
|
|||||||
private ComputerDetails getComputerFromCursor(Cursor c) {
|
private ComputerDetails getComputerFromCursor(Cursor c) {
|
||||||
ComputerDetails details = new ComputerDetails();
|
ComputerDetails details = new ComputerDetails();
|
||||||
|
|
||||||
String uuidStr = c.getString(0);
|
details.uuid = c.getString(0);
|
||||||
try {
|
|
||||||
details.uuid = UUID.fromString(uuidStr);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// We'll delete this entry
|
|
||||||
LimeLog.severe("DB: Corrupted UUID for "+details.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
details.name = c.getString(1);
|
details.name = c.getString(1);
|
||||||
details.localAddress = c.getString(2);
|
details.localAddress = c.getString(2);
|
||||||
details.remoteAddress = c.getString(3);
|
details.remoteAddress = c.getString(3);
|
||||||
@@ -152,8 +142,8 @@ public class ComputerDatabaseManager {
|
|||||||
return computerList;
|
return computerList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComputerDetails getComputerByUUID(UUID uuid) {
|
public ComputerDetails getComputerByUUID(String uuid) {
|
||||||
Cursor c = computerDb.query(COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?", new String[]{ uuid.toString() }, null, null, null);
|
Cursor c = computerDb.query(COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?", new String[]{ uuid }, null, null, null);
|
||||||
if (!c.moveToFirst()) {
|
if (!c.moveToFirst()) {
|
||||||
// No matching computer
|
// No matching computer
|
||||||
c.close();
|
c.close();
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.net.Socket;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import com.limelight.LimeLog;
|
import com.limelight.LimeLog;
|
||||||
@@ -18,6 +17,7 @@ import com.limelight.nvstream.NvConnection;
|
|||||||
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 com.limelight.nvstream.http.NvHTTP;
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
|
import com.limelight.nvstream.http.PairingManager;
|
||||||
import com.limelight.nvstream.mdns.MdnsComputer;
|
import com.limelight.nvstream.mdns.MdnsComputer;
|
||||||
import com.limelight.nvstream.mdns.MdnsDiscoveryListener;
|
import com.limelight.nvstream.mdns.MdnsDiscoveryListener;
|
||||||
import com.limelight.utils.CacheHelper;
|
import com.limelight.utils.CacheHelper;
|
||||||
@@ -241,7 +241,7 @@ public class ComputerManagerService extends Service {
|
|||||||
return idManager.getUniqueId();
|
return idManager.getUniqueId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComputerDetails getComputer(UUID uuid) {
|
public ComputerDetails getComputer(String uuid) {
|
||||||
synchronized (pollingTuples) {
|
synchronized (pollingTuples) {
|
||||||
for (PollingTuple tuple : pollingTuples) {
|
for (PollingTuple tuple : pollingTuples) {
|
||||||
if (uuid.equals(tuple.computer.uuid)) {
|
if (uuid.equals(tuple.computer.uuid)) {
|
||||||
@@ -253,7 +253,7 @@ public class ComputerManagerService extends Service {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateStateForComputer(UUID uuid) {
|
public void invalidateStateForComputer(String uuid) {
|
||||||
synchronized (pollingTuples) {
|
synchronized (pollingTuples) {
|
||||||
for (PollingTuple tuple : pollingTuples) {
|
for (PollingTuple tuple : pollingTuples) {
|
||||||
if (uuid.equals(tuple.computer.uuid)) {
|
if (uuid.equals(tuple.computer.uuid)) {
|
||||||
@@ -360,13 +360,14 @@ public class ComputerManagerService extends Service {
|
|||||||
// Since we're on the same network, we can use STUN to find
|
// Since we're on the same network, we can use STUN to find
|
||||||
// our WAN address, which is also very likely the WAN address
|
// our WAN address, which is also very likely the WAN address
|
||||||
// of the PC. We can use this later to connect remotely.
|
// of the PC. We can use this later to connect remotely.
|
||||||
fakeDetails.remoteAddress = NvConnection.findExternalAddressForMdns();
|
fakeDetails.remoteAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block while we try to fill the details
|
// Block while we try to fill the details
|
||||||
try {
|
try {
|
||||||
runPoll(fakeDetails, true, 0);
|
// We cannot use runPoll() here because it will attempt to persist the state of the machine
|
||||||
if (fakeDetails.state == ComputerDetails.State.ONLINE) {
|
// in the database, which would be bad because we don't have our pinned cert loaded yet.
|
||||||
|
if (pollComputer(fakeDetails)) {
|
||||||
// See if we have record of this PC to pull its pinned cert
|
// See if we have record of this PC to pull its pinned cert
|
||||||
synchronized (pollingTuples) {
|
synchronized (pollingTuples) {
|
||||||
for (PollingTuple tuple : pollingTuples) {
|
for (PollingTuple tuple : pollingTuples) {
|
||||||
@@ -377,10 +378,9 @@ public class ComputerManagerService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fakeDetails.serverCert != null) {
|
// Poll again, possibly with the pinned cert, to get accurate pairing information.
|
||||||
// Poll again with the pinned cert to get accurate pairing information
|
// This will insert the host into the database too.
|
||||||
runPoll(fakeDetails, true, 0);
|
runPoll(fakeDetails, true, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -457,8 +457,12 @@ public class ComputerManagerService extends Service {
|
|||||||
ComputerDetails newDetails = http.getComputerDetails();
|
ComputerDetails newDetails = http.getComputerDetails();
|
||||||
|
|
||||||
// Check if this is the PC we expected
|
// Check if this is the PC we expected
|
||||||
if (details.uuid != null && newDetails.uuid != null &&
|
if (newDetails.uuid == null) {
|
||||||
!details.uuid.equals(newDetails.uuid)) {
|
LimeLog.severe("Polling returned no UUID!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// details.uuid can be null on initial PC add
|
||||||
|
else if (details.uuid != null && !details.uuid.equals(newDetails.uuid)) {
|
||||||
// We got the wrong PC!
|
// We got the wrong PC!
|
||||||
LimeLog.info("Polling returned the wrong PC!");
|
LimeLog.info("Polling returned the wrong PC!");
|
||||||
return null;
|
return null;
|
||||||
@@ -468,7 +472,8 @@ public class ComputerManagerService extends Service {
|
|||||||
newDetails.activeAddress = address;
|
newDetails.activeAddress = address;
|
||||||
|
|
||||||
return newDetails;
|
return newDetails;
|
||||||
} catch (Exception e) {
|
} catch (XmlPullParserException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,8 +702,9 @@ public class ComputerManagerService extends Service {
|
|||||||
public void run() {
|
public void run() {
|
||||||
int emptyAppListResponses = 0;
|
int emptyAppListResponses = 0;
|
||||||
do {
|
do {
|
||||||
// Can't poll if it's not online
|
// Can't poll if it's not online or paired
|
||||||
if (computer.state != ComputerDetails.State.ONLINE) {
|
if (computer.state != ComputerDetails.State.ONLINE ||
|
||||||
|
computer.pairState != PairingManager.PairState.PAIRED) {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.notifyComputerUpdated(computer);
|
listener.notifyComputerUpdated(computer);
|
||||||
}
|
}
|
||||||
@@ -738,12 +744,12 @@ public class ComputerManagerService extends Service {
|
|||||||
// in a row, we'll go ahead and believe it.
|
// in a row, we'll go ahead and believe it.
|
||||||
emptyAppListResponses++;
|
emptyAppListResponses++;
|
||||||
}
|
}
|
||||||
if (appList != null && !appList.isEmpty() &&
|
if (!appList.isEmpty() &&
|
||||||
(!list.isEmpty() || emptyAppListResponses >= EMPTY_LIST_THRESHOLD)) {
|
(!list.isEmpty() || emptyAppListResponses >= EMPTY_LIST_THRESHOLD)) {
|
||||||
// Open the cache file
|
// Open the cache file
|
||||||
OutputStream cacheOut = null;
|
OutputStream cacheOut = null;
|
||||||
try {
|
try {
|
||||||
cacheOut = CacheHelper.openCacheFileForOutput(getCacheDir(), "applist", computer.uuid.toString());
|
cacheOut = CacheHelper.openCacheFileForOutput(getCacheDir(), "applist", computer.uuid);
|
||||||
CacheHelper.writeStringToOutputStream(cacheOut, appList);
|
CacheHelper.writeStringToOutputStream(cacheOut, appList);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -770,7 +776,7 @@ public class ComputerManagerService extends Service {
|
|||||||
listener.notifyComputerUpdated(computer);
|
listener.notifyComputerUpdated(computer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (appList == null || appList.isEmpty()) {
|
else if (appList.isEmpty()) {
|
||||||
LimeLog.warning("Null app list received from "+computer.uuid);
|
LimeLog.warning("Null app list received from "+computer.uuid);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import java.net.InetAddress;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class LegacyDatabaseReader {
|
public class LegacyDatabaseReader {
|
||||||
private static final String COMPUTER_DB_NAME = "computers.db";
|
private static final String COMPUTER_DB_NAME = "computers.db";
|
||||||
@@ -24,14 +23,7 @@ public class LegacyDatabaseReader {
|
|||||||
ComputerDetails details = new ComputerDetails();
|
ComputerDetails details = new ComputerDetails();
|
||||||
|
|
||||||
details.name = c.getString(0);
|
details.name = c.getString(0);
|
||||||
|
details.uuid = c.getString(1);
|
||||||
String uuidStr = c.getString(1);
|
|
||||||
try {
|
|
||||||
details.uuid = UUID.fromString(uuidStr);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// We'll delete this entry
|
|
||||||
LimeLog.severe("DB: Corrupted UUID for " + details.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// An earlier schema defined addresses as byte blobs. We'll
|
// An earlier schema defined addresses as byte blobs. We'll
|
||||||
// gracefully migrate those to strings so we can store DNS names
|
// gracefully migrate those to strings so we can store DNS names
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.widget.TextView;
|
|||||||
import com.limelight.PcView;
|
import com.limelight.PcView;
|
||||||
import com.limelight.R;
|
import com.limelight.R;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
|
import com.limelight.nvstream.http.PairingManager;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -77,6 +78,14 @@ public class PcGridAdapter extends GenericGridAdapter<PcView.ComputerObject> {
|
|||||||
overlayView.setAlpha(0.4f);
|
overlayView.setAlpha(0.4f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// We must check if the status is exactly online and unpaired
|
||||||
|
// to avoid colliding with the loading spinner when status is unknown
|
||||||
|
else if (obj.details.state == ComputerDetails.State.ONLINE &&
|
||||||
|
obj.details.pairState == PairingManager.PairState.NOT_PAIRED) {
|
||||||
|
overlayView.setImageResource(R.drawable.ic_lock);
|
||||||
|
overlayView.setAlpha(1.0f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class DiskAssetLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||||
return CacheHelper.cacheFileExists(cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png");
|
return CacheHelper.cacheFileExists(cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.android.com/topic/performance/graphics/load-bitmap.html
|
// https://developer.android.com/topic/performance/graphics/load-bitmap.html
|
||||||
@@ -65,7 +65,7 @@ public class DiskAssetLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple, int sampleSize) {
|
public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple, int sampleSize) {
|
||||||
File file = CacheHelper.openPath(false, cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png");
|
File file = CacheHelper.openPath(false, cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
|
||||||
|
|
||||||
// Don't bother with anything if it doesn't exist
|
// Don't bother with anything if it doesn't exist
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
@@ -137,7 +137,7 @@ public class DiskAssetLoader {
|
|||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
out = CacheHelper.openCacheFileForOutput(cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png");
|
out = CacheHelper.openCacheFileForOutput(cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
|
||||||
CacheHelper.writeInputStreamToOutputStream(input, out, MAX_ASSET_SIZE);
|
CacheHelper.writeInputStreamToOutputStream(input, out, MAX_ASSET_SIZE);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -151,7 +151,7 @@ public class DiskAssetLoader {
|
|||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
LimeLog.warning("Unable to populate cache with tuple: "+tuple);
|
LimeLog.warning("Unable to populate cache with tuple: "+tuple);
|
||||||
CacheHelper.deleteCacheFile(cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png");
|
CacheHelper.deleteCacheFile(cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class MemoryAssetLoader {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static String constructKey(CachedAppAssetLoader.LoaderTuple tuple) {
|
private static String constructKey(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||||
return tuple.computer.uuid.toString()+"-"+tuple.app.getAppId();
|
return tuple.computer.uuid+"-"+tuple.app.getAppId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple) {
|
public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||||
|
|||||||
@@ -91,14 +91,20 @@ public class AddComputerManually extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doAddPc(String host) {
|
private void doAddPc(String host) {
|
||||||
String msg;
|
|
||||||
boolean wrongSiteLocal = false;
|
boolean wrongSiteLocal = false;
|
||||||
boolean success;
|
boolean success;
|
||||||
|
|
||||||
SpinnerDialog dialog = SpinnerDialog.displayDialog(this, getResources().getString(R.string.title_add_pc),
|
SpinnerDialog dialog = SpinnerDialog.displayDialog(this, getResources().getString(R.string.title_add_pc),
|
||||||
getResources().getString(R.string.msg_add_pc), false);
|
getResources().getString(R.string.msg_add_pc), false);
|
||||||
|
|
||||||
success = managerBinder.addComputerBlocking(host, true);
|
try {
|
||||||
|
success = managerBinder.addComputerBlocking(host, true);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// This can be thrown from OkHttp if the host fails to canonicalize to a valid name.
|
||||||
|
// https://github.com/square/okhttp/blob/okhttp_27/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java#L705
|
||||||
|
e.printStackTrace();
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
if (!success){
|
if (!success){
|
||||||
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
|
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.limelight.preferences;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.DialogPreference;
|
import android.preference.DialogPreference;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ public class PreferenceConfiguration {
|
|||||||
if (resString.equalsIgnoreCase("360p")) {
|
if (resString.equalsIgnoreCase("360p")) {
|
||||||
return 360;
|
return 360;
|
||||||
}
|
}
|
||||||
|
else if (resString.equalsIgnoreCase("480p")) {
|
||||||
|
return 480;
|
||||||
|
}
|
||||||
else if (resString.equalsIgnoreCase("720p")) {
|
else if (resString.equalsIgnoreCase("720p")) {
|
||||||
return 720;
|
return 720;
|
||||||
}
|
}
|
||||||
@@ -103,13 +106,22 @@ public class PreferenceConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int getWidthFromResolutionString(String resString) {
|
private static int getWidthFromResolutionString(String resString) {
|
||||||
return (getHeightFromResolutionString(resString) * 16) / 9;
|
int height = getHeightFromResolutionString(resString);
|
||||||
|
if (height == 480) {
|
||||||
|
// This isn't an exact 16:9 resolution
|
||||||
|
return 854;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (height * 16) / 9;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getResolutionString(int width, int height) {
|
private static String getResolutionString(int width, int height) {
|
||||||
switch (height) {
|
switch (height) {
|
||||||
case 360:
|
case 360:
|
||||||
return "360p";
|
return "360p";
|
||||||
|
case 480:
|
||||||
|
return "480p";
|
||||||
default:
|
default:
|
||||||
case 720:
|
case 720:
|
||||||
return "720p";
|
return "720p";
|
||||||
@@ -139,6 +151,9 @@ public class PreferenceConfiguration {
|
|||||||
if (width * height <= 640 * 360) {
|
if (width * height <= 640 * 360) {
|
||||||
return (int)(1000 * (fps / 30.0));
|
return (int)(1000 * (fps / 30.0));
|
||||||
}
|
}
|
||||||
|
else if (width * height <= 854 * 480) {
|
||||||
|
return (int)(1500 * (fps / 30.0));
|
||||||
|
}
|
||||||
// This covers 1280x720 and 1280x800 too
|
// This covers 1280x720 and 1280x800 too
|
||||||
else if (width * height <= 1366 * 768) {
|
else if (width * height <= 1366 * 768) {
|
||||||
return (int)(5000 * (fps / 30.0));
|
return (int)(5000 * (fps / 30.0));
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ 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 org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ public class ServerHelper {
|
|||||||
intent.putExtra(Game.EXTRA_APP_ID, app.getAppId());
|
intent.putExtra(Game.EXTRA_APP_ID, app.getAppId());
|
||||||
intent.putExtra(Game.EXTRA_APP_HDR, app.isHdrSupported());
|
intent.putExtra(Game.EXTRA_APP_HDR, app.isHdrSupported());
|
||||||
intent.putExtra(Game.EXTRA_UNIQUEID, managerBinder.getUniqueId());
|
intent.putExtra(Game.EXTRA_UNIQUEID, managerBinder.getUniqueId());
|
||||||
intent.putExtra(Game.EXTRA_PC_UUID, computer.uuid.toString());
|
intent.putExtra(Game.EXTRA_PC_UUID, computer.uuid);
|
||||||
intent.putExtra(Game.EXTRA_PC_NAME, computer.name);
|
intent.putExtra(Game.EXTRA_PC_NAME, computer.name);
|
||||||
try {
|
try {
|
||||||
if (computer.serverCert != null) {
|
if (computer.serverCert != null) {
|
||||||
@@ -84,8 +87,9 @@ public class ServerHelper {
|
|||||||
message = parent.getResources().getString(R.string.error_unknown_host);
|
message = parent.getResources().getString(R.string.error_unknown_host);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
message = parent.getResources().getString(R.string.error_404);
|
message = parent.getResources().getString(R.string.error_404);
|
||||||
} catch (Exception e) {
|
} catch (IOException | XmlPullParserException e) {
|
||||||
message = e.getMessage();
|
message = e.getMessage();
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
if (onComplete != null) {
|
if (onComplete != null) {
|
||||||
onComplete.run();
|
onComplete.run();
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public class ShortcutHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void createAppViewShortcut(String id, ComputerDetails details, boolean forceAdd) {
|
public void createAppViewShortcut(String id, ComputerDetails details, boolean forceAdd) {
|
||||||
createAppViewShortcut(id, details.name, details.uuid.toString(), forceAdd);
|
createAppViewShortcut(id, details.name, details.uuid, forceAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
@@ -158,7 +158,7 @@ public class ShortcutHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean createPinnedGameShortcut(String id, Bitmap iconBits, ComputerDetails cDetails, NvApp app) {
|
public boolean createPinnedGameShortcut(String id, Bitmap iconBits, ComputerDetails cDetails, NvApp app) {
|
||||||
return createPinnedGameShortcut(id, iconBits, cDetails.name, cDetails.uuid.toString(), app.getAppName(), Integer.valueOf(app.getAppId()).toString());
|
return createPinnedGameShortcut(id, iconBits, cDetails.name, cDetails.uuid, app.getAppName(), Integer.valueOf(app.getAppId()).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableShortcut(String id, CharSequence reason) {
|
public void disableShortcut(String id, CharSequence reason) {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string-array name="resolution_names">
|
<string-array name="resolution_names">
|
||||||
<item>360p</item>
|
<item>360p</item>
|
||||||
|
<item>480p</item>
|
||||||
<item>720p</item>
|
<item>720p</item>
|
||||||
<item>1080p</item>
|
<item>1080p</item>
|
||||||
<item>1440p</item>
|
<item>1440p</item>
|
||||||
@@ -9,6 +10,7 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="resolution_values" translatable="false">
|
<string-array name="resolution_values" translatable="false">
|
||||||
<item>360p</item>
|
<item>360p</item>
|
||||||
|
<item>480p</item>
|
||||||
<item>720p</item>
|
<item>720p</item>
|
||||||
<item>1080p</item>
|
<item>1080p</item>
|
||||||
<item>1440p</item>
|
<item>1440p</item>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
classpath 'com.android.tools.build:gradle:3.3.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
#Tue May 08 18:56:31 PDT 2018
|
#Tue Feb 05 20:54:22 PST 2019
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||||
|
|||||||
+1
-1
Submodule moonlight-common updated: ee6fd70642...4e4a8f2c4e
Reference in New Issue
Block a user