Compare commits

...

16 Commits

Author SHA1 Message Date
Cameron Gutman 56b814e877 Bump versioncode 2016-10-21 16:22:07 -07:00
Cameron Gutman 628ccd39d6 Fix default context getting picked up falsely during gamepad removal 2016-10-21 16:19:05 -07:00
Cameron Gutman 59db3f9b62 Fix Xbox button behavior quirks on Xbox One S controller 2016-10-21 15:57:00 -07:00
Cameron Gutman 416f922b56 Fix triggers stuck at 50% after controller reconnect 2016-10-21 14:54:21 -07:00
Cameron Gutman b52a86e6cc Fix app grid isRunning icon not displaying 2016-10-21 14:04:31 -07:00
Cameron Gutman e523b5069e Version 4.7.3 2016-10-21 13:48:03 -07:00
Cameron Gutman e8ae8d9807 Manually set pairing state after pairing 2016-10-21 13:47:03 -07:00
Cameron Gutman 64e56a861d Ignore case when sorting apps and PCs 2016-10-21 13:44:59 -07:00
Cameron Gutman c1bcd09c9b Disable launcher shortcuts pending further work 2016-10-21 12:52:37 -07:00
Cameron Gutman 574258804f Update to AS 2.2.2 and SDK 25 2016-10-21 12:50:04 -07:00
Cameron Gutman 21ea3d8a2b Fix 3rd party Xbox controller d-pads 2016-10-21 12:38:55 -07:00
Cameron Gutman 6de4288a85 Fix running app state on GFE 3.1 2016-10-21 12:28:15 -07:00
Cameron Gutman a107b5e652 Add launcher shortcuts and fix duplicate pairing error 2016-10-20 13:09:24 -07:00
Cameron Gutman b02db2c182 Fix JNI build warnings with modern NDKs 2016-10-19 20:47:23 -07:00
Cameron Gutman f8a04cda7a Version 4.7.2 2016-10-05 18:53:36 -07:00
Cameron Gutman 226e8edefc Update common jar to 55f0114 2016-10-05 18:49:57 -07:00
13 changed files with 303 additions and 67 deletions
+21 -15
View File
@@ -72,13 +72,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/nonRoot/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/assets" type="java-test-resource" />
@@ -86,6 +79,13 @@
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testNonRoot/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestNonRoot/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
@@ -107,13 +107,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
@@ -121,19 +114,32 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndkBuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" />
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="bcprov-jdk15on-1.52" level="project" />
<orderEntry type="library" exported="" name="bcpkix-jdk15on-1.52" level="project" />
+5 -5
View File
@@ -4,15 +4,15 @@ import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.3"
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
minSdkVersion 16
targetSdkVersion 24
targetSdkVersion 25
versionName "4.7.1"
versionCode = 105
versionName "4.7.3"
versionCode = 108
}
productFlavors {
Binary file not shown.
+75 -29
View File
@@ -11,12 +11,14 @@ import com.limelight.grid.AppGridAdapter;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
import com.limelight.nvstream.http.PairingManager;
import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.ui.AdapterFragment;
import com.limelight.ui.AdapterFragmentCallbacks;
import com.limelight.utils.CacheHelper;
import com.limelight.utils.Dialog;
import com.limelight.utils.ServerHelper;
import com.limelight.utils.ShortcutHelper;
import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper;
@@ -43,14 +45,16 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
public class AppView extends Activity implements AdapterFragmentCallbacks {
private AppGridAdapter appGridAdapter;
private String uuidString;
private ShortcutHelper shortcutHelper;
private ComputerDetails computer;
private ComputerManagerService.ApplistPoller poller;
private SpinnerDialog blockingLoadSpinner;
private SpinnerDialog blockingLoadSpinner, blockingServerinfoSpinner;
private String lastRawApplist;
private int lastRunningAppId;
private boolean suspendGridUpdates;
private boolean inForeground;
private boolean launchedFromShortcut;
private final static int START_OR_RESUME_ID = 1;
private final static int QUIT_ID = 2;
@@ -59,6 +63,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
public final static String NAME_EXTRA = "Name";
public final static String UUID_EXTRA = "UUID";
public final static String SHORTCUT_EXTRA = "Shortcut";
private ComputerManagerService.ComputerManagerBinder managerBinder;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@@ -90,12 +95,15 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
return;
}
// Load the app grid with cached data (if possible).
// This must be done _before_ startComputerUpdates()
// so the initial serverinfo response can update the running
// icon.
populateAppGridWithCache();
// Start updates
startComputerUpdates();
// Load the app grid with cached data (if possible)
populateAppGridWithCache();
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -132,7 +140,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
managerBinder.startPolling(new ComputerManagerListener() {
@Override
public void notifyComputerUpdated(ComputerDetails details) {
public void notifyComputerUpdated(final ComputerDetails details) {
// Do nothing if updates are suspended
if (suspendGridUpdates) {
return;
@@ -157,6 +165,48 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
return;
}
// Close immediately if the PC is no longer paired
if (details.state == ComputerDetails.State.ONLINE && details.pairState != PairingManager.PairState.PAIRED) {
AppView.this.runOnUiThread(new Runnable() {
@Override
public void run() {
// Disable shortcuts referencing this PC for now
shortcutHelper.disableShortcut(details.uuid.toString(),
getResources().getString(R.string.scut_not_paired));
// Display a toast to the user and quit the activity
Toast.makeText(AppView.this, getResources().getText(R.string.scut_not_paired), Toast.LENGTH_SHORT).show();
finish();
}
});
return;
}
if (launchedFromShortcut) {
if (details.state == ComputerDetails.State.ONLINE) {
if (blockingServerinfoSpinner != null) {
blockingServerinfoSpinner.dismiss();
blockingServerinfoSpinner = null;
}
if (details.runningGameId != 0) {
AppView.this.runOnUiThread(new Runnable() {
@Override
public void run() {
// We have to finish this activity here otherwise we'll get into a loop
// when the user hits back
finish();
// When launched from shortcut, resume the running game
ServerHelper.doStart(AppView.this, new NvApp("app", details.runningGameId), computer, managerBinder);
}
});
return;
}
}
}
// App list is the same or empty
if (details.rawAppList == null || details.rawAppList.equals(lastRawApplist)) {
@@ -175,6 +225,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
try {
updateUiWithAppList(NvHTTP.getAppListByReader(new StringReader(details.rawAppList)));
updateUiWithServerinfo(details);
if (blockingLoadSpinner != null) {
blockingLoadSpinner.dismiss();
@@ -208,6 +259,8 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
shortcutHelper = new ShortcutHelper(this);
String locale = PreferenceConfiguration.readPreferences(this).language;
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
Configuration config = new Configuration(getResources().getConfiguration());
@@ -221,6 +274,15 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
uuidString = getIntent().getStringExtra(UUID_EXTRA);
launchedFromShortcut = getIntent().getBooleanExtra(SHORTCUT_EXTRA, false);
if (launchedFromShortcut) {
// Display blocking loading spinner
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
getResources().getString(R.string.applist_connect_msg), true);
}
shortcutHelper.reportShortcutUsed(uuidString);
String labelText = getResources().getString(R.string.title_applist)+" "+getIntent().getStringExtra(NAME_EXTRA);
TextView label = (TextView) findViewById(R.id.appListText);
setTitle(labelText);
@@ -282,27 +344,14 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
stopComputerUpdates();
}
private int getRunningAppId() {
int runningAppId = -1;
for (int i = 0; i < appGridAdapter.getCount(); i++) {
AppObject app = (AppObject) appGridAdapter.getItem(i);
if (app.app.getIsRunning()) {
runningAppId = app.app.getAppId();
break;
}
}
return runningAppId;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
AppObject selectedApp = (AppObject) appGridAdapter.getItem(info.position);
int runningAppId = getRunningAppId();
if (runningAppId != -1) {
if (runningAppId == selectedApp.app.getAppId()) {
if (lastRunningAppId != 0) {
if (lastRunningAppId == selectedApp.app.getAppId()) {
menu.add(Menu.NONE, START_OR_RESUME_ID, 1, getResources().getString(R.string.applist_menu_resume));
menu.add(Menu.NONE, QUIT_ID, 2, getResources().getString(R.string.applist_menu_quit));
}
@@ -378,19 +427,19 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
AppObject existingApp = (AppObject) appGridAdapter.getItem(i);
// There can only be one or zero apps running.
if (existingApp.app.getIsRunning() &&
if (existingApp.isRunning &&
existingApp.app.getAppId() == details.runningGameId) {
// This app was running and still is, so we're done now
return;
}
else if (existingApp.app.getAppId() == details.runningGameId) {
// This app wasn't running but now is
existingApp.app.setIsRunning(true);
existingApp.isRunning = true;
updated = true;
}
else if (existingApp.app.getIsRunning()) {
else if (existingApp.isRunning) {
// This app was running but now isn't
existingApp.app.setIsRunning(false);
existingApp.isRunning = false;
updated = true;
}
else {
@@ -420,10 +469,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
AppObject existingApp = (AppObject) appGridAdapter.getItem(i);
if (existingApp.app.getAppId() == app.getAppId()) {
// Found the app; update its properties
if (existingApp.app.getIsRunning() != app.getIsRunning()) {
existingApp.app.setIsRunning(app.getIsRunning());
updated = true;
}
if (!existingApp.app.getAppName().equals(app.getAppName())) {
existingApp.app.setAppName(app.getAppName());
updated = true;
@@ -493,7 +538,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
AppObject app = (AppObject) appGridAdapter.getItem(pos);
// Only open the context menu if something is running, otherwise start it
if (getRunningAppId() != -1) {
if (lastRunningAppId != 0) {
openContextMenu(arg1);
} else {
ServerHelper.doStart(AppView.this, app.app, computer, managerBinder);
@@ -506,6 +551,7 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
public class AppObject {
public final NvApp app;
public boolean isRunning;
public AppObject(NvApp app) {
if (app == null) {
@@ -24,6 +24,7 @@ import com.limelight.ui.AdapterFragment;
import com.limelight.ui.AdapterFragmentCallbacks;
import com.limelight.utils.Dialog;
import com.limelight.utils.ServerHelper;
import com.limelight.utils.ShortcutHelper;
import com.limelight.utils.UiHelper;
import android.app.Activity;
@@ -52,6 +53,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
public class PcView extends Activity implements AdapterFragmentCallbacks {
private RelativeLayout noPcFoundLayout;
private PcGridAdapter pcGridAdapter;
private ShortcutHelper shortcutHelper;
private ComputerManagerService.ComputerManagerBinder managerBinder;
private boolean freezeUpdates, runningPolling, inForeground;
private final ServiceConnection serviceConnection = new ServiceConnection() {
@@ -142,6 +144,8 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
shortcutHelper = new ShortcutHelper(this);
String locale = PreferenceConfiguration.readPreferences(this).language;
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
Configuration config = new Configuration(getResources().getConfiguration());
@@ -334,6 +338,9 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
else if (pairState == PairingManager.PairState.FAILED) {
message = getResources().getString(R.string.pair_fail);
}
else if (pairState == PairingManager.PairState.ALREADY_IN_PROGRESS) {
message = getResources().getString(R.string.pair_already_in_progress);
}
else if (pairState == PairingManager.PairState.PAIRED) {
// Just navigate to the app view without displaying a toast
message = null;
@@ -366,6 +373,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
if (toastSuccess) {
// Open the app list after a successful pairing attempt
computer.pairState = PairState.PAIRED;
doAppList(computer);
}
else {
@@ -486,6 +494,8 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
return;
}
shortcutHelper.createAppViewShortcut(computer.uuid.toString(), computer);
Intent i = new Intent(this, AppView.class);
i.putExtra(AppView.NAME_EXTRA, computer.name);
i.putExtra(AppView.UUID_EXTRA, computer.uuid.toString());
@@ -558,6 +568,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
ComputerObject computer = (ComputerObject) pcGridAdapter.getItem(i);
if (details.equals(computer.details)) {
// Disable or delete shortcuts referencing this PC
shortcutHelper.disableShortcut(details.uuid.toString(),
getResources().getString(R.string.scut_deleted_pc));
pcGridAdapter.removeComputer(computer);
pcGridAdapter.notifyDataSetChanged();
@@ -5,6 +5,7 @@ import android.hardware.input.InputManager;
import android.os.SystemClock;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.Toast;
@@ -415,21 +416,27 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
return context;
}
private InputDeviceContext getContextForDevice(InputDevice dev) {
private InputDeviceContext getContextForEvent(InputEvent event) {
// Unknown devices use the default context
if (dev == null) {
if (event.getDeviceId() == 0) {
return defaultContext;
}
else if (event.getDevice() == null) {
// During device removal, sometimes we can get events after the
// input device has been destroyed. In this case we'll see a
// != 0 device ID but no device attached.
return null;
}
// Return the existing context if it exists
InputDeviceContext context = inputDeviceContexts.get(dev.getId());
InputDeviceContext context = inputDeviceContexts.get(event.getDeviceId());
if (context != null) {
return context;
}
// Otherwise create a new context
context = createInputDeviceContextForDevice(dev);
inputDeviceContexts.put(dev.getId(), context);
context = createInputDeviceContextForDevice(event.getDevice());
inputDeviceContexts.put(event.getDeviceId(), context);
return context;
}
@@ -627,6 +634,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
default:
// Other buttons are mapped correctly
}
// The Xbox button is sent as MENU
if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
return KeyEvent.KEYCODE_BUTTON_MODE;
}
}
if (context.hatXAxis != -1 && context.hatYAxis != -1) {
@@ -642,7 +654,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
else if (context.hatXAxis == -1 &&
context.hatYAxis == -1 &&
context.isXboxController &&
/* FIXME: There's no good way to know for sure if xpad is bound
to this device, so we won't use the name to validate if these
scancodes should be mapped to DPAD
context.isXboxController &&
*/
event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
// If there's not a proper Xbox controller mapping, we'll translate the raw d-pad
// scan codes into proper key codes
@@ -732,9 +749,23 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
if (context.leftTriggerAxis != -1 && context.rightTriggerAxis != -1) {
// Android sends an initial 0 value for trigger axes even if the trigger
// should be negative when idle. After the first touch, the axes will go back
// to normal behavior, so ignore triggersIdleNegative for each trigger until
// first touch.
if (lt != 0) {
context.leftTriggerUsed = true;
}
if (rt != 0) {
context.rightTriggerUsed = true;
}
if (context.triggersIdleNegative) {
lt = (lt + 1) / 2;
rt = (rt + 1) / 2;
if (context.leftTriggerUsed) {
lt = (lt + 1) / 2;
}
if (context.rightTriggerUsed) {
rt = (rt + 1) / 2;
}
}
if (lt <= context.triggerDeadzone) {
@@ -770,7 +801,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
public boolean handleMotionEvent(MotionEvent event) {
InputDeviceContext context = getContextForDevice(event.getDevice());
InputDeviceContext context = getContextForEvent(event);
if (context == null) {
return true;
}
float lsX = 0, lsY = 0, rsX = 0, rsY = 0, rt = 0, lt = 0, hatX = 0, hatY = 0;
// We purposefully ignore the historical values in the motion event as it makes
@@ -842,7 +877,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
public boolean handleButtonUp(KeyEvent event) {
InputDeviceContext context = getContextForDevice(event.getDevice());
InputDeviceContext context = getContextForEvent(event);
if (context == null) {
return true;
}
int keyCode = handleRemapping(context, event);
if (keyCode == 0) {
@@ -867,7 +905,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
break;
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
if (SystemClock.uptimeMillis() - context.startDownTime > ControllerHandler.START_DOWN_TIME_MOUSE_MODE_MS) {
// Sometimes we'll get a spurious key up event on controller disconnect.
// Make sure it's real by checking that the key is actually down before taking
// any action.
if ((context.inputMap & ControllerPacket.PLAY_FLAG) != 0 &&
SystemClock.uptimeMillis() - context.startDownTime > ControllerHandler.START_DOWN_TIME_MOUSE_MODE_MS) {
toggleMouseEmulation(context);
}
context.inputMap &= ~ControllerPacket.PLAY_FLAG;
@@ -965,7 +1007,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
public boolean handleButtonDown(KeyEvent event) {
InputDeviceContext context = getContextForDevice(event.getDevice());
InputDeviceContext context = getContextForEvent(event);
if (context == null) {
return true;
}
int keyCode = handleRemapping(context, event);
if (keyCode == 0) {
@@ -1153,6 +1198,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
public int leftTriggerAxis = -1;
public int rightTriggerAxis = -1;
public boolean triggersIdleNegative;
public boolean leftTriggerUsed, rightTriggerUsed;
public int hatXAxis = -1;
public int hatYAxis = -1;
@@ -65,7 +65,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
Collections.sort(itemList, new Comparator<AppView.AppObject>() {
@Override
public int compare(AppView.AppObject lhs, AppView.AppObject rhs) {
return lhs.app.getAppName().compareTo(rhs.app.getAppName());
return lhs.app.getAppName().toLowerCase().compareTo(rhs.app.getAppName().toLowerCase());
}
});
}
@@ -101,7 +101,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
@Override
public boolean populateOverlayView(ImageView overlayView, AppView.AppObject obj) {
if (obj.app.getIsRunning()) {
if (obj.isRunning) {
// Show the play button overlay
overlayView.setImageResource(R.drawable.ic_play);
return true;
@@ -28,7 +28,7 @@ public class PcGridAdapter extends GenericGridAdapter<PcView.ComputerObject> {
Collections.sort(itemList, new Comparator<PcView.ComputerObject>() {
@Override
public int compare(PcView.ComputerObject lhs, PcView.ComputerObject rhs) {
return lhs.details.name.compareTo(rhs.details.name);
return lhs.details.name.toLowerCase().compareTo(rhs.details.name.toLowerCase());
}
});
}
@@ -0,0 +1,115 @@
package com.limelight.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.os.Build;
import com.limelight.AppView;
import com.limelight.R;
import com.limelight.nvstream.http.ComputerDetails;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class ShortcutHelper {
private final ShortcutManager sm;
private final Context context;
public ShortcutHelper(Context context) {
this.context = context;
if (Build.VERSION.SDK_INT >= 25) {
sm = context.getSystemService(ShortcutManager.class);
}
else {
sm = null;
}
}
@TargetApi(25)
private void reapShortcutsForDynamicAdd() {
List<ShortcutInfo> dynamicShortcuts = sm.getDynamicShortcuts();
while (dynamicShortcuts.size() >= sm.getMaxShortcutCountPerActivity()) {
ShortcutInfo maxRankShortcut = dynamicShortcuts.get(0);
for (ShortcutInfo scut : dynamicShortcuts) {
if (maxRankShortcut.getRank() < scut.getRank()) {
maxRankShortcut = scut;
}
}
sm.removeDynamicShortcuts(Arrays.asList(maxRankShortcut.getId()));
}
}
@TargetApi(25)
private List<ShortcutInfo> getAllShortcuts() {
LinkedList<ShortcutInfo> list = new LinkedList<>();
list.addAll(sm.getDynamicShortcuts());
list.addAll(sm.getPinnedShortcuts());
return list;
}
@TargetApi(25)
private ShortcutInfo getInfoForId(String id) {
List<ShortcutInfo> shortcuts = getAllShortcuts();
for (ShortcutInfo info : shortcuts) {
if (info.getId().equals(id)) {
return info;
}
}
return null;
}
public void reportShortcutUsed(String id) {
if (Build.VERSION.SDK_INT >= 25) {
ShortcutInfo sinfo = getInfoForId(id);
if (sinfo != null) {
sm.reportShortcutUsed(id);
}
}
}
public void createAppViewShortcut(String id, ComputerDetails details) {
if (Build.VERSION.SDK_INT >= 25) {
Intent i = new Intent(context, AppView.class);
i.putExtra(AppView.NAME_EXTRA, details.name);
i.putExtra(AppView.UUID_EXTRA, details.uuid.toString());
i.putExtra(AppView.SHORTCUT_EXTRA, true);
i.setAction(Intent.ACTION_DEFAULT);
ShortcutInfo sinfo = new ShortcutInfo.Builder(context, id)
.setIntent(i)
.setShortLabel(details.name)
.setLongLabel(details.name)
.build();
ShortcutInfo existingSinfo = getInfoForId(id);
if (existingSinfo != null) {
// Update in place
sm.updateShortcuts(Arrays.asList(sinfo));
sm.enableShortcuts(Arrays.asList(id));
}
else {
// Reap shortcuts to make space for this new one
reapShortcutsForDynamicAdd();
// Add the new shortcut
//TODO: Testing and proper icon - sm.addDynamicShortcuts(Arrays.asList(sinfo));
}
}
}
public void disableShortcut(String id, CharSequence reason) {
if (Build.VERSION.SDK_INT >= 25) {
ShortcutInfo sinfo = getInfoForId(id);
if (sinfo != null) {
sm.disableShortcuts(Arrays.asList(id), reason);
}
}
}
}
@@ -15,6 +15,8 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <android/log.h>
#define EVDEV_MAX_EVENT_SIZE 24
@@ -19,7 +19,8 @@ Java_com_limelight_nvstream_av_audio_OpusDecoder_init(JNIEnv *env, jobject this,
ChannelCount = channelCount;
jni_mapping_data = (*env)->GetByteArrayElements(env, mapping, 0);
ret = nv_opus_init(sampleRate, channelCount, streams, coupledStreams, jni_mapping_data);
ret = nv_opus_init(sampleRate, channelCount, streams, coupledStreams,
(const unsigned char*)jni_mapping_data);
(*env)->ReleaseByteArrayElements(env, mapping, jni_mapping_data, JNI_ABORT);
return ret;
@@ -49,7 +50,8 @@ Java_com_limelight_nvstream_av_audio_OpusDecoder_decode(
if (indata != NULL) {
jni_input_data = (*env)->GetByteArrayElements(env, indata, 0);
ret = nv_opus_decode(&jni_input_data[inoff], inlen, (jshort*)jni_pcm_data, SamplesPerChannel);
ret = nv_opus_decode((unsigned char*)&jni_input_data[inoff], inlen,
(jshort*)jni_pcm_data, SamplesPerChannel);
// The input data isn't changed so it can be safely aborted
(*env)->ReleaseByteArrayElements(env, indata, jni_input_data, JNI_ABORT);
+5
View File
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Shortcut strings -->
<string name="scut_deleted_pc">PC deleted</string>
<string name="scut_not_paired">PC not paired</string>
<!-- PC view menu entries -->
<string name="pcview_menu_app_list">View Game List</string>
@@ -16,6 +19,7 @@
<string name="pair_pairing_msg">Please enter the following PIN on the target PC:</string>
<string name="pair_incorrect_pin">Incorrect PIN</string>
<string name="pair_fail">Pairing failed</string>
<string name="pair_already_in_progress">Pairing already in progress</string>
<!-- WOL messages -->
<string name="wol_pc_online">Computer is online</string>
@@ -63,6 +67,7 @@
<!-- AppList activity -->
<string name="title_applist">Apps on</string>
<string name="applist_connect_msg">Connecting to PC…</string>
<string name="applist_menu_resume">Resume Session</string>
<string name="applist_menu_quit">Quit Session</string>
<string name="applist_menu_quit_and_start">Quit Current Game and Start</string>
+1 -1
View File
@@ -4,7 +4,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.android.tools.build:gradle:2.2.2'
}
}