Compare commits

..
13 Commits
53 changed files with 240 additions and 69 deletions

No files matched your search

+13 -8
View File
@@ -5,16 +5,18 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 26 compileSdkVersion 26
buildToolsVersion '26.0.0' buildToolsVersion '26.0.1'
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 26 targetSdkVersion 26
versionName "5.1" versionName "5.1.2"
versionCode = 128 versionCode = 130
} }
flavorDimensions "root"
productFlavors { productFlavors {
root { root {
// Android O has native mouse capture, so don't show the rooted // Android O has native mouse capture, so don't show the rooted
@@ -25,6 +27,8 @@ android {
ndk { ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64" abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"
} }
dimension "root"
} }
nonRoot { nonRoot {
@@ -32,6 +36,8 @@ android {
ndk { ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64" abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"
} }
dimension "root"
} }
} }
@@ -54,10 +60,9 @@ android {
} }
dependencies { dependencies {
compile 'org.bouncycastle:bcprov-jdk15on:1.52' implementation 'org.bouncycastle:bcprov-jdk15on:1.52'
compile 'org.bouncycastle:bcpkix-jdk15on:1.52' implementation 'org.bouncycastle:bcpkix-jdk15on:1.52'
compile files('libs/jcodec-0.1.9-patched.jar') implementation files('libs/jcodec-0.1.9-patched.jar')
debugCompile project(path:':moonlight-common', configuration:'debug') implementation project(':moonlight-common')
releaseCompile project(path:':moonlight-common', configuration:'release')
} }
+2 -1
View File
@@ -29,7 +29,8 @@
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:isGame="true" android:isGame="true"
android:banner="@drawable/atv_banner" android:banner="@drawable/atv_banner"
android:icon="@drawable/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<!-- Samsung multi-window support --> <!-- Samsung multi-window support -->
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+11 -1
View File
@@ -214,7 +214,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Initialize the MediaCodec helper before creating the decoder // Initialize the MediaCodec helper before creating the decoder
MediaCodecHelper.initializeWithContext(this); MediaCodecHelper.initializeWithContext(this);
decoderRenderer = new MediaCodecDecoderRenderer(prefConfig.videoFormat, prefConfig.bitrate); decoderRenderer = new MediaCodecDecoderRenderer(prefConfig.videoFormat, prefConfig.bitrate, prefConfig.batterySaver);
// Display a message to the user if H.265 was forced on but we still didn't find a decoder // Display a message to the user if H.265 was forced on but we still didn't find a decoder
if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) { if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) {
@@ -944,6 +944,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
displayedFailureDialog = true; displayedFailureDialog = true;
LimeLog.severe(stage+" failed: "+errorCode); LimeLog.severe(stage+" failed: "+errorCode);
// If video initialization failed and the surface is still valid, display extra information for the user
if (stage.contains("video") && streamView.getHolder().getSurface().isValid()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(Game.this, "Video decoder failed to initialize. Your device may not support the selected resolution.", Toast.LENGTH_LONG).show();
}
});
}
Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title), Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title),
getResources().getString(R.string.conn_error_msg)+" "+stage, true); getResources().getString(R.string.conn_error_msg)+" "+stage, true);
} }
@@ -1,8 +1,10 @@
package com.limelight.binding.audio; package com.limelight.binding.audio;
import android.media.AudioAttributes;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioTrack; import android.media.AudioTrack;
import android.os.Build;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.nvstream.av.audio.AudioRenderer; import com.limelight.nvstream.av.audio.AudioRenderer;
@@ -12,10 +14,58 @@ public class AndroidAudioRenderer implements AudioRenderer {
private AudioTrack track; private AudioTrack track;
private AudioTrack createAudioTrack(int channelConfig, int bufferSize, boolean lowLatency) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return new AudioTrack(AudioManager.STREAM_MUSIC,
48000,
channelConfig,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
}
else {
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME);
AudioFormat format = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(48000)
.setChannelMask(channelConfig)
.build();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// Use FLAG_LOW_LATENCY on L through N
if (lowLatency) {
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
.setAudioFormat(format)
.setAudioAttributes(attributesBuilder.build())
.setTransferMode(AudioTrack.MODE_STREAM)
.setBufferSizeInBytes(bufferSize);
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
if (lowLatency) {
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
}
return trackBuilder.build();
}
else {
return new AudioTrack(attributesBuilder.build(),
format,
bufferSize,
AudioTrack.MODE_STREAM,
AudioManager.AUDIO_SESSION_ID_GENERATE);
}
}
}
@Override @Override
public int setup(int audioConfiguration) { public int setup(int audioConfiguration) {
int channelConfig; int channelConfig;
int bufferSize;
int bytesPerFrame; int bytesPerFrame;
switch (audioConfiguration) switch (audioConfiguration)
@@ -38,44 +88,76 @@ public class AndroidAudioRenderer implements AudioRenderer {
// do this on many devices and it lowers audio latency. // do this on many devices and it lowers audio latency.
// We'll try the small buffer size first and if it fails, // We'll try the small buffer size first and if it fails,
// use the recommended larger buffer size. // use the recommended larger buffer size.
try {
// Buffer two frames of audio if possible
bufferSize = bytesPerFrame * 2;
track = new AudioTrack(AudioManager.STREAM_MUSIC, for (int i = 0; i < 4; i++) {
48000, boolean lowLatency;
channelConfig, int bufferSize;
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
track.play();
} catch (Exception e) {
// Try to release the AudioTrack if we got far enough
try {
if (track != null) {
track.release();
}
} catch (Exception ignored) {}
// Now try the larger buffer size // We will try:
bufferSize = Math.max(AudioTrack.getMinBufferSize(48000, // 1) Small buffer, low latency mode
// 2) Large buffer, low latency mode
// 3) Small buffer, standard mode
// 4) Large buffer, standard mode
switch (i) {
case 0:
case 1:
lowLatency = true;
break;
case 2:
case 3:
lowLatency = false;
break;
default:
// Unreachable
throw new IllegalStateException();
}
switch (i) {
case 0:
case 2:
bufferSize = bytesPerFrame * 2;
break;
case 1:
case 3:
// Try the larger buffer size
bufferSize = Math.max(AudioTrack.getMinBufferSize(48000,
channelConfig, channelConfig,
AudioFormat.ENCODING_PCM_16BIT), AudioFormat.ENCODING_PCM_16BIT),
bytesPerFrame * 2); bytesPerFrame * 2);
// Round to next frame // Round to next frame
bufferSize = (((bufferSize + (bytesPerFrame - 1)) / bytesPerFrame) * bytesPerFrame); bufferSize = (((bufferSize + (bytesPerFrame - 1)) / bytesPerFrame) * bytesPerFrame);
break;
default:
// Unreachable
throw new IllegalStateException();
}
track = new AudioTrack(AudioManager.STREAM_MUSIC, // Skip low latency options if hardware sample rate isn't 48000Hz
48000, if (AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC) != 48000 && lowLatency) {
channelConfig, continue;
AudioFormat.ENCODING_PCM_16BIT, }
bufferSize,
AudioTrack.MODE_STREAM); try {
track.play(); track = createAudioTrack(channelConfig, bufferSize, lowLatency);
track.play();
// Successfully created working AudioTrack. We're done here.
LimeLog.info("Audio track configuration: "+bufferSize+" "+lowLatency);
break;
} catch (Exception e) {
// Try to release the AudioTrack if we got far enough
try {
if (track != null) {
track.release();
track = null;
}
} catch (Exception ignored) {}
}
} }
LimeLog.info("Audio track buffer size: "+bufferSize);
return 0; return 0;
} }
@@ -51,6 +51,10 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
private boolean needsBaselineSpsHack; private boolean needsBaselineSpsHack;
private SeqParameterSet savedSps; private SeqParameterSet savedSps;
private RendererException initialException;
private long initialExceptionTimestamp;
private static final int EXCEPTION_REPORT_DELAY_MS = 3000;
private long lastTimestampUs; private long lastTimestampUs;
private long decoderTimeMs; private long decoderTimeMs;
private long totalTimeMs; private long totalTimeMs;
@@ -105,12 +109,18 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
this.renderTarget = renderTarget; this.renderTarget = renderTarget;
} }
public MediaCodecDecoderRenderer(int videoFormat, int bitrate) { public MediaCodecDecoderRenderer(int videoFormat, int bitrate, boolean batterySaver) {
//dumpDecoders(); //dumpDecoders();
this.bitrate = bitrate; this.bitrate = bitrate;
spinnerThreads = new Thread[Runtime.getRuntime().availableProcessors()]; // Disable spinner threads in battery saver mode
if (batterySaver) {
spinnerThreads = new Thread[0];
}
else {
spinnerThreads = new Thread[Runtime.getRuntime().availableProcessors()];
}
avcDecoder = findAvcDecoder(); avcDecoder = findAvcDecoder();
if (avcDecoder != null) { if (avcDecoder != null) {
@@ -294,13 +304,31 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
} }
} }
// Only throw if the surface is still around and we're not stopping // Only throw if we're not stopping
if (!stopping && renderTarget.getSurface().isValid()) { if (!stopping) {
if (buf != null || codecFlags != 0) { //
throw new RendererException(this, e, buf, codecFlags); // There seems to be a race condition with decoder/surface teardown causing some
// decoders to to throw IllegalStateExceptions even before 'stopping' is set.
// To workaround this while allowing real exceptions to propagate, we will eat the
// first exception. If we are still receiving exceptions 3 seconds later, we will
// throw the original exception again.
//
if (initialException != null) {
// This isn't the first time we've had an exception processing video
if (System.currentTimeMillis() - initialExceptionTimestamp >= EXCEPTION_REPORT_DELAY_MS) {
// It's been over 3 seconds and we're still getting exceptions. Throw the original now.
throw initialException;
}
} }
else { else {
throw new RendererException(this, e); // This is the first exception we've hit
if (buf != null || codecFlags != 0) {
initialException = new RendererException(this, e, buf, codecFlags);
}
else {
initialException = new RendererException(this, e);
}
initialExceptionTimestamp = System.currentTimeMillis();
} }
} }
} }
@@ -311,7 +339,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
@Override @Override
public void run() { public void run() {
BufferInfo info = new BufferInfo(); BufferInfo info = new BufferInfo();
while (!isInterrupted()) { while (!stopping) {
try { try {
// Try to output a frame // Try to output a frame
int outIndex = videoDecoder.dequeueOutputBuffer(info, 50000); int outIndex = videoDecoder.dequeueOutputBuffer(info, 50000);
@@ -369,7 +397,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
public void run() { public void run() {
// This thread exists to keep the CPU at a higher DVFS state on devices // This thread exists to keep the CPU at a higher DVFS state on devices
// where the governor scales clock speed sporadically, causing dropped frames. // where the governor scales clock speed sporadically, causing dropped frames.
while (!isInterrupted()) { while (!stopping) {
try { try {
Thread.sleep(0, 1); Thread.sleep(0, 1);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -418,17 +446,21 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
startSpinnerThreads(); startSpinnerThreads();
} }
// !!! May be called even if setup()/start() fails !!!
public void prepareForStop() { public void prepareForStop() {
// Let the decoding code know to ignore codec exceptions now // Let the decoding code know to ignore codec exceptions now
stopping = true; stopping = true;
// Halt the rendering thread
if (rendererThread != null) {
rendererThread.interrupt();
}
} }
@Override @Override
public void stop() { public void stop() {
stopping = true; // May be called already, but we'll call it now to be safe
prepareForStop();
// Halt the rendering thread
rendererThread.interrupt();
try { try {
// Invalidate pending decode buffers // Invalidate pending decode buffers
@@ -653,13 +685,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
inputBufferIndex = dequeueInputBuffer(); inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) { if (inputBufferIndex < 0) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
buf = getEmptyInputBuffer(inputBufferIndex); buf = getEmptyInputBuffer(inputBufferIndex);
if (buf == null) { if (buf == null) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
// Write the annex B header // Write the annex B header
@@ -687,13 +719,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
inputBufferIndex = dequeueInputBuffer(); inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) { if (inputBufferIndex < 0) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
buf = getEmptyInputBuffer(inputBufferIndex); buf = getEmptyInputBuffer(inputBufferIndex);
if (buf == null) { if (buf == null) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
if (needsBaselineSpsHack) { if (needsBaselineSpsHack) {
@@ -726,13 +758,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
inputBufferIndex = dequeueInputBuffer(); inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) { if (inputBufferIndex < 0) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
buf = getEmptyInputBuffer(inputBufferIndex); buf = getEmptyInputBuffer(inputBufferIndex);
if (buf == null) { if (buf == null) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
// When we get the PPS, submit the VPS and SPS together with // When we get the PPS, submit the VPS and SPS together with
@@ -751,13 +783,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
inputBufferIndex = dequeueInputBuffer(); inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) { if (inputBufferIndex < 0) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
buf = getEmptyInputBuffer(inputBufferIndex); buf = getEmptyInputBuffer(inputBufferIndex);
if (buf == null) { if (buf == null) {
// We're being torn down now // We're being torn down now
return MoonBridge.DR_OK; return MoonBridge.DR_NEED_IDR;
} }
} }
@@ -900,6 +932,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
str += "Is Exynos 4: "+renderer.isExynos4+"\n"; str += "Is Exynos 4: "+renderer.isExynos4+"\n";
str += "/proc/cpuinfo:\n";
try {
str += MediaCodecHelper.readCpuinfo();
} catch (Exception e) {
str += e.getMessage();
}
str += "Full decoder dump:\n"; str += "Full decoder dump:\n";
try { try {
str += MediaCodecHelper.dumpDecoders(); str += MediaCodecHelper.dumpDecoders();
@@ -23,6 +23,7 @@ public class PreferenceConfiguration {
private static final String USB_DRIVER_PREF_SRING = "checkbox_usb_driver"; private static final String USB_DRIVER_PREF_SRING = "checkbox_usb_driver";
private static final String VIDEO_FORMAT_PREF_STRING = "video_format"; private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls"; private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
private static final String BATTERY_SAVER_PREF_STRING = "checkbox_battery_saver";
private static final int BITRATE_DEFAULT_720_30 = 5; private static final int BITRATE_DEFAULT_720_30 = 5;
private static final int BITRATE_DEFAULT_720_60 = 10; private static final int BITRATE_DEFAULT_720_60 = 10;
@@ -45,6 +46,7 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_USB_DRIVER = true; private static final boolean DEFAULT_USB_DRIVER = true;
private static final String DEFAULT_VIDEO_FORMAT = "auto"; private static final String DEFAULT_VIDEO_FORMAT = "auto";
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false; private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
private static final boolean DEFAULT_BATTERY_SAVER = false;
public static final int FORCE_H265_ON = -1; public static final int FORCE_H265_ON = -1;
public static final int AUTOSELECT_H265 = 0; public static final int AUTOSELECT_H265 = 0;
@@ -58,6 +60,7 @@ public class PreferenceConfiguration {
public String language; public String language;
public boolean listMode, smallIconMode, multiController, enable51Surround, usbDriver; public boolean listMode, smallIconMode, multiController, enable51Surround, usbDriver;
public boolean onscreenController; public boolean onscreenController;
public boolean batterySaver;
public static int getDefaultBitrate(String resFpsString) { public static int getDefaultBitrate(String resFpsString) {
if (resFpsString.equals("720p30")) { if (resFpsString.equals("720p30")) {
@@ -188,6 +191,7 @@ public class PreferenceConfiguration {
config.enable51Surround = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND); config.enable51Surround = prefs.getBoolean(ENABLE_51_SURROUND_PREF_STRING, DEFAULT_ENABLE_51_SURROUND);
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER); config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT); config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
config.batterySaver = prefs.getBoolean(BATTERY_SAVER_PREF_STRING, DEFAULT_BATTERY_SAVER);
return config; return config;
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_pc_scut_background"/>
<foreground android:drawable="@mipmap/ic_pc_scut_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_pc_scut_background"/>
<foreground android:drawable="@mipmap/ic_pc_scut_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#565C64</color>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_pc_scut_background">#FFFFFF</color>
</resources>
+2
View File
@@ -104,6 +104,8 @@
<string name="title_checkbox_stretch_video">Stretch video to full-screen</string> <string name="title_checkbox_stretch_video">Stretch video to full-screen</string>
<string name="title_checkbox_disable_warnings">Disable warning messages</string> <string name="title_checkbox_disable_warnings">Disable warning messages</string>
<string name="summary_checkbox_disable_warnings">Disable on-screen connection warning messages while streaming</string> <string name="summary_checkbox_disable_warnings">Disable on-screen connection warning messages while streaming</string>
<string name="title_checkbox_battery_saver">Battery saver</string>
<string name="summary_checkbox_battery_saver">Uses less battery, but may increase stuttering</string>
<string name="category_audio_settings">Audio Settings</string> <string name="category_audio_settings">Audio Settings</string>
<string name="title_checkbox_51_surround">Enable 5.1 surround sound</string> <string name="title_checkbox_51_surround">Enable 5.1 surround sound</string>
+3 -3
View File
@@ -21,9 +21,9 @@
android:title="@string/title_checkbox_stretch_video" android:title="@string/title_checkbox_stretch_video"
android:defaultValue="false" /> android:defaultValue="false" />
<CheckBoxPreference <CheckBoxPreference
android:key="checkbox_disable_warnings" android:key="checkbox_battery_saver"
android:title="@string/title_checkbox_disable_warnings" android:title="@string/title_checkbox_battery_saver"
android:summary="@string/summary_checkbox_disable_warnings" android:summary="@string/summary_checkbox_battery_saver"
android:defaultValue="false" /> android:defaultValue="false" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/category_audio_settings"> <PreferenceCategory android:title="@string/category_audio_settings">
+1 -1
View File
@@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:3.0.0-beta2'
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
#Thu Mar 02 18:32:01 PST 2017 #Sat Aug 12 15:52:56 PDT 2017
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-3.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip