- 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>
74 lines
2.4 KiB
Java
74 lines
2.4 KiB
Java
package com.miniabs;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
|
|
import android.content.Context;
|
|
import android.media.AudioManager;
|
|
import android.media.MediaPlayer;
|
|
import android.os.PowerManager;
|
|
|
|
/** Android's own MediaPlayer: every Android version. No speed control (Android 2.x can't). */
|
|
final class MediaPlayerEngine implements Engine, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,
|
|
MediaPlayer.OnErrorListener, MediaPlayer.OnBufferingUpdateListener {
|
|
|
|
private final MediaPlayer mp = new MediaPlayer();
|
|
private Listener listener;
|
|
private int buffered;
|
|
|
|
MediaPlayerEngine(Context c) {
|
|
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
|
mp.setWakeMode(c.getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
|
|
mp.setOnPreparedListener(this);
|
|
mp.setOnCompletionListener(this);
|
|
mp.setOnErrorListener(this);
|
|
mp.setOnBufferingUpdateListener(this);
|
|
}
|
|
|
|
public void setListener(Listener l) { listener = l; }
|
|
|
|
public void setSource(File file, String url) throws Exception {
|
|
if (file != null) {
|
|
FileInputStream in = new FileInputStream(file);
|
|
try { mp.setDataSource(in.getFD()); } finally { in.close(); }
|
|
} else {
|
|
mp.setDataSource(url);
|
|
}
|
|
}
|
|
|
|
public void prepare() { mp.prepareAsync(); }
|
|
|
|
public void start() { mp.start(); }
|
|
|
|
public void pause() { mp.pause(); }
|
|
|
|
public void seekTo(int ms) { mp.seekTo(ms); }
|
|
|
|
public int position() { return mp.getCurrentPosition(); }
|
|
|
|
public int duration() { return Math.max(0, mp.getDuration()); }
|
|
|
|
public int bufferedPercent() { return buffered; }
|
|
|
|
public void setVolume(float v) { mp.setVolume(v, v); }
|
|
|
|
public void setSpeed(float speed, boolean skipSilence) {}
|
|
|
|
public void release() {
|
|
listener = null;
|
|
try { mp.reset(); } catch (Exception ignored) {}
|
|
try { mp.release(); } catch (Exception ignored) {}
|
|
}
|
|
|
|
public void onPrepared(MediaPlayer p) { if (listener != null) listener.onPrepared(this); }
|
|
|
|
public void onCompletion(MediaPlayer p) { if (listener != null) listener.onCompletion(this); }
|
|
|
|
public boolean onError(MediaPlayer p, int what, int extra) {
|
|
if (listener != null) listener.onError(this, "Erro de reprodución (" + what + "/" + extra + ").", false);
|
|
return true;
|
|
}
|
|
|
|
public void onBufferingUpdate(MediaPlayer p, int percent) { buffered = percent; }
|
|
}
|