Podlite 1.12: a build for Android 4.1 (Xperia J) with ExoPlayer, speed and skip silences
- One build per Android level, as in Tenda and Plexamp Lite: build/Podlite.apk (Android 2.2+, versionCode 1308) and build/Podlite-api16.apk (Android 4.1+, 1316), from shared src/ plus platform/api8 or platform/api16; build.sh now runs on the local toolchain (aapt2, dx or R8, signapk.py; the JKS key converted for the run). - Android 4.1 build: ExoPlayer 2.18.7 behind an Engine interface, with playback speed (player header) and skipping silences (Settings), a 3-minute buffer and MediaPlayer as fallback for audio it can't decode; a notification and lock screen with the cover and buttons; Holo; a menu button on phones without a Menu key; metered networks for "download on Wi-Fi only". - Both builds: tlskit's Http.abort fix (a finished response's pooled connection is no longer closed under a later request); the lock screen's and newer headsets' play/pause keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b2ca212c45
commit
666a7eb8cd
32 files changed
+1267
-123
No files matched your search
@@ -451,19 +451,25 @@ public final class Http {
|
||||
// ------------------------------------------------------------------ body streams
|
||||
|
||||
private static final class FixedStream extends InputStream {
|
||||
private final Conn c; private long left; private final boolean keepAlive; private boolean closed;
|
||||
private final Conn c; private long left; private final boolean keepAlive; private volatile boolean closed;
|
||||
|
||||
FixedStream(Conn c, long len, boolean keepAlive) {
|
||||
this.c = c; this.left = len; this.keepAlive = keepAlive;
|
||||
if (len == 0) finish(true);
|
||||
}
|
||||
|
||||
private void finish(boolean complete) {
|
||||
private synchronized void finish(boolean complete) {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
if (complete && keepAlive) release(c); else c.close();
|
||||
}
|
||||
|
||||
synchronized void abort() {
|
||||
if (closed) return; // done: the connection may already be back in the pool, serving someone else
|
||||
closed = true;
|
||||
try { c.socket.close(); } catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
@Override public int read() throws IOException {
|
||||
byte[] one = new byte[1];
|
||||
int n = read(one, 0, 1);
|
||||
@@ -490,16 +496,22 @@ public final class Http {
|
||||
|
||||
private static final class ChunkedStream extends InputStream {
|
||||
private final Conn c; private final boolean keepAlive;
|
||||
private long chunkLeft = 0; private boolean eof; private boolean closed;
|
||||
private long chunkLeft = 0; private boolean eof; private volatile boolean closed;
|
||||
|
||||
ChunkedStream(Conn c, boolean keepAlive) { this.c = c; this.keepAlive = keepAlive; }
|
||||
|
||||
private void finish(boolean complete) {
|
||||
private synchronized void finish(boolean complete) {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
if (complete && keepAlive) release(c); else c.close();
|
||||
}
|
||||
|
||||
synchronized void abort() {
|
||||
if (closed) return; // done: the connection may already be back in the pool, serving someone else
|
||||
closed = true;
|
||||
try { c.socket.close(); } catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private boolean nextChunk() throws IOException {
|
||||
if (eof) return false;
|
||||
String line = readLine(c.in);
|
||||
@@ -551,7 +563,7 @@ public final class Http {
|
||||
}
|
||||
|
||||
private static final class EofStream extends InputStream {
|
||||
private final Conn c; private boolean closed;
|
||||
private final Conn c; private volatile boolean closed;
|
||||
EofStream(Conn c) { this.c = c; }
|
||||
|
||||
@Override public int read() throws IOException {
|
||||
@@ -568,21 +580,25 @@ public final class Http {
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override public void close() {
|
||||
@Override public synchronized void close() {
|
||||
if (!closed) { closed = true; c.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
/** Close one in-flight response's socket from another thread (used to abort streams). */
|
||||
public static void abort(Response r) {
|
||||
if (r == null) return;
|
||||
InputStream b = r.body;
|
||||
Conn c = null;
|
||||
if (b instanceof FixedStream) c = ((FixedStream) b).c;
|
||||
else if (b instanceof ChunkedStream) c = ((ChunkedStream) b).c;
|
||||
else if (b instanceof EofStream) c = ((EofStream) b).c;
|
||||
if (c != null) {
|
||||
synchronized void abort() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
try { c.socket.close(); } catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
/** Close one in-flight response's socket from another thread (used to abort streams). A response that has
|
||||
* already been read to the end is left alone: its connection went back to the pool and may be carrying
|
||||
* another request by now (closing it cut read-ahead downloads short: "Unexpected end of stream"). */
|
||||
public static void abort(Response r) {
|
||||
if (r == null) return;
|
||||
InputStream b = r.body;
|
||||
if (b instanceof FixedStream) ((FixedStream) b).abort();
|
||||
else if (b instanceof ChunkedStream) ((ChunkedStream) b).abort();
|
||||
else if (b instanceof EofStream) ((EofStream) b).abort();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user