Android: Support Android Embedding V2 (#109)

* Bump AGP & Gradle
* Migrate the project to Android Embedding to V2
This commit is contained in:
Sebastian Roth 2020-06-08 12:20:14 +01:00 committed by GitHub
parent 4dee0906db
commit 8f146e559a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 74 deletions

View File

@ -8,7 +8,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:3.6.3'
}
}

View File

@ -3,7 +3,6 @@ package com.ryanheise.just_audio;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
@ -26,31 +25,28 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import io.flutter.Log;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AudioPlayer implements MethodCallHandler, Player.EventListener, MetadataOutput {
static final String TAG = "AudioPlayer";
private final Registrar registrar;
private final Context context;
private final MethodChannel methodChannel;
private final EventChannel eventChannel;
private EventSink eventSink;
private final String id;
private volatile PlaybackState state;
private long updateTime;
private long updatePosition;
@ -70,11 +66,15 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
private IcyInfo icyInfo;
private IcyHeaders icyHeaders;
private final SimpleExoPlayer player;
private SimpleExoPlayer player;
private final Handler handler = new Handler();
private final Runnable bufferWatcher = new Runnable() {
@Override
public void run() {
if (player == null) {
return;
}
long newBufferedPosition = player.getBufferedPosition();
if (newBufferedPosition != bufferedPosition) {
bufferedPosition = newBufferedPosition;
@ -92,13 +92,15 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
}
};
public AudioPlayer(final Registrar registrar, final String id) {
this.registrar = registrar;
this.context = registrar.activeContext();
this.id = id;
methodChannel = new MethodChannel(registrar.messenger(), "com.ryanheise.just_audio.methods." + id);
private final Runnable onDispose;
public AudioPlayer(final Context applicationContext, final BinaryMessenger messenger,
final String id, final Runnable onDispose) {
this.context = applicationContext;
this.onDispose = onDispose;
methodChannel = new MethodChannel(messenger, "com.ryanheise.just_audio.methods." + id);
methodChannel.setMethodCallHandler(this);
eventChannel = new EventChannel(registrar.messenger(), "com.ryanheise.just_audio.events." + id);
eventChannel = new EventChannel(messenger, "com.ryanheise.just_audio.events." + id);
eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
@Override
public void onListen(final Object arguments, final EventSink eventSink) {
@ -111,10 +113,6 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
}
});
state = PlaybackState.none;
player = new SimpleExoPlayer.Builder(context).build();
player.addMetadataOutput(this);
player.addListener(this);
}
private void startWatchingBuffer() {
@ -227,6 +225,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
@Override
public void onMethodCall(final MethodCall call, final Result result) {
ensurePlayerInitialized();
final List<?> args = (List<?>) call.arguments;
try {
switch (call.method) {
@ -278,6 +278,7 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
break;
case "dispose":
dispose();
onDispose.run();
result.success(null);
break;
default:
@ -293,6 +294,14 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
}
}
private void ensurePlayerInitialized() {
if (player == null) {
player = new SimpleExoPlayer.Builder(context).build();
player.addMetadataOutput(this);
player.addListener(this);
}
}
private void broadcastPlaybackEvent() {
final ArrayList<Object> event = new ArrayList<Object>();
event.add(state.ordinal());
@ -382,7 +391,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
true
);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, httpDataSourceFactory);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
httpDataSourceFactory);
Uri uri = Uri.parse(url);
String extension = getLowerCaseExtension(uri);
if (extension.equals("mpd")) {
@ -435,7 +445,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
player.setPlayWhenReady(true);
break;
default:
throw new IllegalStateException("Cannot call play from connecting/none states (" + state + ")");
throw new IllegalStateException(
"Cannot call play from connecting/none states (" + state + ")");
}
}
@ -448,7 +459,8 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
transition(PlaybackState.paused);
break;
default:
throw new IllegalStateException("Can call pause only from playing and buffering states (" + state + ")");
throw new IllegalStateException(
"Can call pause only from playing and buffering states (" + state + ")");
}
}
@ -500,10 +512,13 @@ public class AudioPlayer implements MethodCallHandler, Player.EventListener, Met
}
public void dispose() {
if (player != null) {
player.release();
player = null;
buffering = false;
transition(PlaybackState.none);
}
}
private void abortSeek() {
if (seekResult != null) {

View File

@ -1,41 +1,57 @@
package com.ryanheise.just_audio;
import io.flutter.plugin.common.MethodCall;
import android.content.Context;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import java.util.List;
/** JustAudioPlugin */
public class JustAudioPlugin implements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.ryanheise.just_audio.methods");
channel.setMethodCallHandler(new JustAudioPlugin(registrar));
/**
* JustAudioPlugin
*/
public class JustAudioPlugin implements FlutterPlugin {
private MethodChannel channel;
private MethodCallHandlerImpl methodCallHandler;
public JustAudioPlugin() {
}
private Registrar registrar;
public JustAudioPlugin(Registrar registrar) {
this.registrar = registrar;
/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
final JustAudioPlugin plugin = new JustAudioPlugin();
plugin.startListening(registrar.context(), registrar.messenger());
registrar.addViewDestroyListener(
view -> {
plugin.stopListening();
return false;
});
}
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "init":
final List<?> args = (List<?>)call.arguments;
String id = (String)args.get(0);
new AudioPlayer(registrar, id);
result.success(null);
break;
case "setIosCategory":
result.success(null);
break;
default:
result.notImplemented();
break;
}
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
startListening(binding.getApplicationContext(), binding.getBinaryMessenger());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
stopListening();
}
private void startListening(Context applicationContext, BinaryMessenger messenger) {
methodCallHandler = new MethodCallHandlerImpl(applicationContext, messenger);
channel = new MethodChannel(messenger, "com.ryanheise.just_audio.methods");
channel.setMethodCallHandler(methodCallHandler);
}
private void stopListening() {
methodCallHandler.dispose();
methodCallHandler = null;
channel.setMethodCallHandler(null);
}
}

View File

@ -0,0 +1,53 @@
package com.ryanheise.just_audio;
import android.content.Context;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MethodCallHandlerImpl implements MethodCallHandler {
private final Context applicationContext;
private final BinaryMessenger messenger;
private final Map<String, AudioPlayer> players = new HashMap<>();
public MethodCallHandlerImpl(Context applicationContext,
BinaryMessenger messenger) {
this.applicationContext = applicationContext;
this.messenger = messenger;
}
@Override
public void onMethodCall(MethodCall call, @NonNull Result result) {
switch (call.method) {
case "init":
final List<String> ids = call.arguments();
String id = ids.get(0);
players.put(id, new AudioPlayer(applicationContext, messenger, id,
() -> players.remove(id)
));
result.success(null);
break;
case "setIosCategory":
result.success(null);
break;
default:
result.notImplemented();
break;
}
}
void dispose() {
for (AudioPlayer player : players.values()) {
player.dispose();
}
players.clear();
}
}

View File

@ -5,7 +5,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:3.6.3'
}
}

View File

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
#Sun Jun 07 15:20:36 BST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

View File

@ -451,7 +451,7 @@ class AudioPlayer {
/// * [AudioPlaybackState.none]
/// * [AudioPlaybackState.connecting]
Future<void> dispose() async {
await _invokeMethod('dispose');
await _invokeMethod('dispose', [_id]);
if (_cacheFile?.existsSync() == true) {
_cacheFile?.deleteSync();
}