Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1d7f556fd | |||
| 1e70e1d329 | |||
| e02a009635 | |||
| bd6ff35603 | |||
| 1cb7727dc7 | |||
| 0c73e3d0ae | |||
| 6371d364e1 | |||
| ded9c9140d | |||
| 7c8a108e28 | |||
| 2a18ffcdba | |||
| 381d0d5e81 |
+2
-2
@@ -11,8 +11,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
|
||||
versionName "3.1.6"
|
||||
versionCode = 61
|
||||
versionName "3.1.8"
|
||||
versionCode = 63
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
|
||||
Binary file not shown.
@@ -16,6 +16,10 @@
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
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 -->
|
||||
<activity
|
||||
@@ -24,6 +28,7 @@
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
|
||||
<category android:name="tv.ouya.intent.category.APP" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
package com.limelight;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.StringReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.computers.ComputerManagerListener;
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
import com.limelight.grid.AppGridAdapter;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.preferences.PreferenceConfiguration;
|
||||
@@ -26,10 +21,8 @@ import com.limelight.utils.SpinnerDialog;
|
||||
import com.limelight.utils.UiHelper;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
@@ -306,6 +306,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
||||
addr = computer.remoteIp;
|
||||
}
|
||||
else {
|
||||
LimeLog.warning("Unknown reachability - using local IP");
|
||||
addr = computer.localIp;
|
||||
}
|
||||
|
||||
httpConn = new NvHTTP(addr,
|
||||
managerBinder.getUniqueId(),
|
||||
@@ -431,6 +435,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
else if (computer.reachability == ComputerDetails.Reachability.REMOTE) {
|
||||
addr = computer.remoteIp;
|
||||
}
|
||||
else {
|
||||
LimeLog.warning("Unknown reachability - using local IP");
|
||||
addr = computer.localIp;
|
||||
}
|
||||
|
||||
httpConn = new NvHTTP(addr,
|
||||
managerBinder.getUniqueId(),
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.limelight.binding.input;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.hardware.input.InputManager;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
@@ -52,8 +50,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
deadzonePercentage = 10;
|
||||
|
||||
int[] ids = InputDevice.getDeviceIds();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
InputDevice dev = InputDevice.getDevice(ids[i]);
|
||||
for (int id : ids) {
|
||||
InputDevice dev = InputDevice.getDevice(id);
|
||||
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0 ||
|
||||
(dev.getSources() & InputDevice.SOURCE_GAMEPAD) != 0) {
|
||||
// This looks like a gamepad, but we'll check X and Y to be sure
|
||||
@@ -275,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) {
|
||||
// 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
|
||||
@@ -298,7 +305,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
else if (devName.contains("Fire TV Remote") || devName.contains("Nexus Remote")) {
|
||||
// It's only a remote if it doesn't any sticks
|
||||
if (!context.hasJoystickAxes) {
|
||||
context.isRemote = true;
|
||||
context.ignoreBack = true;
|
||||
}
|
||||
}
|
||||
// SHIELD controllers will use small stick deadzones
|
||||
@@ -306,10 +313,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
context.leftStickDeadzoneRadius = 0.07f;
|
||||
context.rightStickDeadzoneRadius = 0.07f;
|
||||
}
|
||||
// Samsung's face buttons appear as a non-virtual button so we'll classify them as remotes
|
||||
// so the back button gets passed through to exit streaming
|
||||
// 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.isRemote = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,8 +362,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
// Return a valid keycode, 0 to consume, or -1 to not consume the event
|
||||
// Device MAY BE NULL
|
||||
private int handleRemapping(ControllerContext context, KeyEvent event) {
|
||||
// For remotes, don't capture the back button
|
||||
if (context.isRemote) {
|
||||
// Don't capture the back button if configured
|
||||
if (context.ignoreBack) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||
return -1;
|
||||
}
|
||||
@@ -394,6 +407,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
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) {
|
||||
switch (event.getKeyCode()) {
|
||||
@@ -815,9 +838,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener {
|
||||
|
||||
public boolean isDualShock4;
|
||||
public boolean isXboxController;
|
||||
public boolean isServal;
|
||||
public boolean backIsStart;
|
||||
public boolean modeIsSelect;
|
||||
public boolean isRemote;
|
||||
public boolean ignoreBack;
|
||||
public boolean hasJoystickAxes;
|
||||
|
||||
public boolean assignedControllerNumber;
|
||||
|
||||
@@ -134,11 +134,14 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
if (buf != null || codecFlags != 0) {
|
||||
throw new RendererException(this, e, buf, codecFlags);
|
||||
}
|
||||
else {
|
||||
throw new RendererException(this, e);
|
||||
// Only throw if this happens at the beginning of a stream
|
||||
if (totalFrames < 60) {
|
||||
if (buf != null || codecFlags != 0) {
|
||||
throw new RendererException(this, e, buf, codecFlags);
|
||||
}
|
||||
else {
|
||||
throw new RendererException(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,19 +486,49 @@ public class MediaCodecDecoderRenderer extends EnhancedDecoderRenderer {
|
||||
LimeLog.info("Patching num_ref_frames in SPS");
|
||||
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) {
|
||||
// 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.
|
||||
LimeLog.info("Adding bitstream restrictions");
|
||||
|
||||
sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
|
||||
sps.vuiParams.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = true;
|
||||
// GFE 2.5.11 started sending bitstream restrictions
|
||||
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_bits_per_mb_denom = 1;
|
||||
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;
|
||||
sps.vuiParams.bitstreamRestriction.max_dec_frame_buffering = 1;
|
||||
|
||||
// log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more
|
||||
// conservative values by GFE 2.5.11. We'll let those values stand.
|
||||
}
|
||||
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
|
||||
|
||||
@@ -393,7 +393,7 @@ public class ComputerManagerService extends Service {
|
||||
private boolean fastPollIp(InetAddress addr) {
|
||||
Socket s = new Socket();
|
||||
try {
|
||||
s.connect(new InetSocketAddress(addr, NvHTTP.PORT), FAST_POLL_TIMEOUT);
|
||||
s.connect(new InetSocketAddress(addr, NvHTTP.HTTPS_PORT), FAST_POLL_TIMEOUT);
|
||||
s.close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
@@ -639,7 +639,7 @@ public class ComputerManagerService extends Service {
|
||||
if (cacheOut != null) {
|
||||
cacheOut.close();
|
||||
}
|
||||
} catch (IOException e) {}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
// Update the computer
|
||||
|
||||
@@ -27,7 +27,7 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
|
||||
|
||||
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);
|
||||
|
||||
int dpi = activity.getResources().getDisplayMetrics().densityDpi;
|
||||
|
||||
@@ -26,7 +26,7 @@ public class NetworkAssetLoader {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = http.getBoxArt(tuple.app);
|
||||
} catch (IOException e) {}
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
if (in != null) {
|
||||
LimeLog.info("Network asset load complete: " + tuple);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.limelight.preferences;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class PreferenceConfiguration {
|
||||
@@ -69,9 +70,18 @@ public class PreferenceConfiguration {
|
||||
|
||||
public static boolean getDefaultSmallMode(Context context) {
|
||||
PackageManager manager = context.getPackageManager();
|
||||
if (manager != null && manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
|
||||
if (manager != null) {
|
||||
// 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
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.2.2'
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user