diff --git a/packages/video_player/video_player_android/CHANGELOG.md b/packages/video_player/video_player_android/CHANGELOG.md index 52d6dca4366..e87cb3296b8 100644 --- a/packages/video_player/video_player_android/CHANGELOG.md +++ b/packages/video_player/video_player_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.14 + +* Restructures internal logic for player creation and tracking. + ## 2.8.13 * Bumps com.android.tools.build:gradle to 8.12.1. diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java index 5899b7501a1..1bac72cf7bd 100644 --- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java +++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/Messages.java @@ -65,18 +65,6 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { @Retention(CLASS) @interface CanIgnoreReturnValue {} - /** Pigeon equivalent of VideoViewType. */ - public enum PlatformVideoViewType { - TEXTURE_VIEW(0), - PLATFORM_VIEW(1); - - final int index; - - PlatformVideoViewType(final int index) { - this.index = index; - } - } - /** Pigeon equivalent of video_platform_interface's VideoFormat. */ public enum PlatformVideoFormat { DASH(0), @@ -163,7 +151,7 @@ ArrayList toList() { } /** Generated class from Pigeon that represents data sent in messages. */ - public static final class CreateMessage { + public static final class CreationOptions { private @NonNull String uri; public @NonNull String getUri() { @@ -210,18 +198,8 @@ public void setUserAgent(@Nullable String setterArg) { this.userAgent = setterArg; } - private @Nullable PlatformVideoViewType viewType; - - public @Nullable PlatformVideoViewType getViewType() { - return viewType; - } - - public void setViewType(@Nullable PlatformVideoViewType setterArg) { - this.viewType = setterArg; - } - /** Constructor is non-public to enforce null safety; use Builder. */ - CreateMessage() {} + CreationOptions() {} @Override public boolean equals(Object o) { @@ -231,17 +209,16 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - CreateMessage that = (CreateMessage) o; + CreationOptions that = (CreationOptions) o; return uri.equals(that.uri) && Objects.equals(formatHint, that.formatHint) && httpHeaders.equals(that.httpHeaders) - && Objects.equals(userAgent, that.userAgent) - && Objects.equals(viewType, that.viewType); + && Objects.equals(userAgent, that.userAgent); } @Override public int hashCode() { - return Objects.hash(uri, formatHint, httpHeaders, userAgent, viewType); + return Objects.hash(uri, formatHint, httpHeaders, userAgent); } public static final class Builder { @@ -278,38 +255,28 @@ public static final class Builder { return this; } - private @Nullable PlatformVideoViewType viewType; - - @CanIgnoreReturnValue - public @NonNull Builder setViewType(@Nullable PlatformVideoViewType setterArg) { - this.viewType = setterArg; - return this; - } - - public @NonNull CreateMessage build() { - CreateMessage pigeonReturn = new CreateMessage(); + public @NonNull CreationOptions build() { + CreationOptions pigeonReturn = new CreationOptions(); pigeonReturn.setUri(uri); pigeonReturn.setFormatHint(formatHint); pigeonReturn.setHttpHeaders(httpHeaders); pigeonReturn.setUserAgent(userAgent); - pigeonReturn.setViewType(viewType); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList<>(5); + ArrayList toListResult = new ArrayList<>(4); toListResult.add(uri); toListResult.add(formatHint); toListResult.add(httpHeaders); toListResult.add(userAgent); - toListResult.add(viewType); return toListResult; } - static @NonNull CreateMessage fromList(@NonNull ArrayList pigeonVar_list) { - CreateMessage pigeonResult = new CreateMessage(); + static @NonNull CreationOptions fromList(@NonNull ArrayList pigeonVar_list) { + CreationOptions pigeonResult = new CreationOptions(); Object uri = pigeonVar_list.get(0); pigeonResult.setUri((String) uri); Object formatHint = pigeonVar_list.get(1); @@ -318,8 +285,98 @@ ArrayList toList() { pigeonResult.setHttpHeaders((Map) httpHeaders); Object userAgent = pigeonVar_list.get(3); pigeonResult.setUserAgent((String) userAgent); - Object viewType = pigeonVar_list.get(4); - pigeonResult.setViewType((PlatformVideoViewType) viewType); + return pigeonResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class TexturePlayerIds { + private @NonNull Long playerId; + + public @NonNull Long getPlayerId() { + return playerId; + } + + public void setPlayerId(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"playerId\" is null."); + } + this.playerId = setterArg; + } + + private @NonNull Long textureId; + + public @NonNull Long getTextureId() { + return textureId; + } + + public void setTextureId(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"textureId\" is null."); + } + this.textureId = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + TexturePlayerIds() {} + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TexturePlayerIds that = (TexturePlayerIds) o; + return playerId.equals(that.playerId) && textureId.equals(that.textureId); + } + + @Override + public int hashCode() { + return Objects.hash(playerId, textureId); + } + + public static final class Builder { + + private @Nullable Long playerId; + + @CanIgnoreReturnValue + public @NonNull Builder setPlayerId(@NonNull Long setterArg) { + this.playerId = setterArg; + return this; + } + + private @Nullable Long textureId; + + @CanIgnoreReturnValue + public @NonNull Builder setTextureId(@NonNull Long setterArg) { + this.textureId = setterArg; + return this; + } + + public @NonNull TexturePlayerIds build() { + TexturePlayerIds pigeonReturn = new TexturePlayerIds(); + pigeonReturn.setPlayerId(playerId); + pigeonReturn.setTextureId(textureId); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList<>(2); + toListResult.add(playerId); + toListResult.add(textureId); + return toListResult; + } + + static @NonNull TexturePlayerIds fromList(@NonNull ArrayList pigeonVar_list) { + TexturePlayerIds pigeonResult = new TexturePlayerIds(); + Object playerId = pigeonVar_list.get(0); + pigeonResult.setPlayerId((Long) playerId); + Object textureId = pigeonVar_list.get(1); + pigeonResult.setTextureId((Long) textureId); return pigeonResult; } } @@ -427,19 +484,16 @@ private PigeonCodec() {} protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 129: - { - Object value = readValue(buffer); - return value == null ? null : PlatformVideoViewType.values()[((Long) value).intValue()]; - } - case (byte) 130: { Object value = readValue(buffer); return value == null ? null : PlatformVideoFormat.values()[((Long) value).intValue()]; } - case (byte) 131: + case (byte) 130: return PlatformVideoViewCreationParams.fromList((ArrayList) readValue(buffer)); + case (byte) 131: + return CreationOptions.fromList((ArrayList) readValue(buffer)); case (byte) 132: - return CreateMessage.fromList((ArrayList) readValue(buffer)); + return TexturePlayerIds.fromList((ArrayList) readValue(buffer)); case (byte) 133: return PlaybackState.fromList((ArrayList) readValue(buffer)); default: @@ -449,18 +503,18 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { @Override protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { - if (value instanceof PlatformVideoViewType) { + if (value instanceof PlatformVideoFormat) { stream.write(129); - writeValue(stream, value == null ? null : ((PlatformVideoViewType) value).index); - } else if (value instanceof PlatformVideoFormat) { - stream.write(130); writeValue(stream, value == null ? null : ((PlatformVideoFormat) value).index); } else if (value instanceof PlatformVideoViewCreationParams) { - stream.write(131); + stream.write(130); writeValue(stream, ((PlatformVideoViewCreationParams) value).toList()); - } else if (value instanceof CreateMessage) { + } else if (value instanceof CreationOptions) { + stream.write(131); + writeValue(stream, ((CreationOptions) value).toList()); + } else if (value instanceof TexturePlayerIds) { stream.write(132); - writeValue(stream, ((CreateMessage) value).toList()); + writeValue(stream, ((TexturePlayerIds) value).toList()); } else if (value instanceof PlaybackState) { stream.write(133); writeValue(stream, ((PlaybackState) value).toList()); @@ -476,7 +530,10 @@ public interface AndroidVideoPlayerApi { void initialize(); @NonNull - Long create(@NonNull CreateMessage msg); + Long createForPlatformView(@NonNull CreationOptions options); + + @NonNull + TexturePlayerIds createForTextureView(@NonNull CreationOptions options); void dispose(@NonNull Long playerId); @@ -530,7 +587,32 @@ static void setUp( BasicMessageChannel channel = new BasicMessageChannel<>( binaryMessenger, - "dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.create" + "dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.createForPlatformView" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + ArrayList args = (ArrayList) message; + CreationOptions optionsArg = (CreationOptions) args.get(0); + try { + Long output = api.createForPlatformView(optionsArg); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.createForTextureView" + messageChannelSuffix, getCodec()); if (api != null) { @@ -538,9 +620,9 @@ static void setUp( (message, reply) -> { ArrayList wrapped = new ArrayList<>(); ArrayList args = (ArrayList) message; - CreateMessage msgArg = (CreateMessage) args.get(0); + CreationOptions optionsArg = (CreationOptions) args.get(0); try { - Long output = api.create(msgArg); + TexturePlayerIds output = api.createForTextureView(optionsArg); wrapped.add(0, output); } catch (Throwable exception) { wrapped = wrapError(exception); diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java index daf9207c967..db0e811b55b 100644 --- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java +++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java @@ -14,8 +14,9 @@ import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; import io.flutter.plugins.videoplayer.Messages.AndroidVideoPlayerApi; -import io.flutter.plugins.videoplayer.Messages.CreateMessage; +import io.flutter.plugins.videoplayer.Messages.CreationOptions; import io.flutter.plugins.videoplayer.Messages.PlatformVideoFormat; +import io.flutter.plugins.videoplayer.Messages.TexturePlayerIds; import io.flutter.plugins.videoplayer.Messages.VideoPlayerInstanceApi; import io.flutter.plugins.videoplayer.platformview.PlatformVideoViewFactory; import io.flutter.plugins.videoplayer.platformview.PlatformViewVideoPlayer; @@ -27,14 +28,8 @@ public class VideoPlayerPlugin implements FlutterPlugin, AndroidVideoPlayerApi { private static final String TAG = "VideoPlayerPlugin"; private final LongSparseArray videoPlayers = new LongSparseArray<>(); private FlutterState flutterState; - private final VideoPlayerOptions options = new VideoPlayerOptions(); - - // TODO(stuartmorgan): Decouple identifiers for platform views and texture views. - /** - * The next non-texture player ID, initialized to a high number to avoid collisions with texture - * IDs (which are generated separately). - */ - private Long nextPlatformViewPlayerId = Long.MAX_VALUE; + private final VideoPlayerOptions sharedOptions = new VideoPlayerOptions(); + private long nextPlayerIdentifier = 1; /** Register this with the v2 embedding for the plugin to respond to lifecycle callbacks. */ public VideoPlayerPlugin() {} @@ -90,16 +85,48 @@ public void initialize() { } @Override - public @NonNull Long create(@NonNull CreateMessage arg) { - final @NonNull String uri = arg.getUri(); - final VideoAsset videoAsset; + public @NonNull Long createForPlatformView(@NonNull CreationOptions options) { + final VideoAsset videoAsset = videoAssetWithOptions(options); + + long id = nextPlayerIdentifier++; + VideoPlayer videoPlayer = + PlatformViewVideoPlayer.create( + flutterState.applicationContext, + VideoPlayerEventCallbacks.bindTo(createEventChannel(id)), + videoAsset, + sharedOptions); + + registerPlayerInstance(videoPlayer, id); + return id; + } + + @Override + public @NonNull TexturePlayerIds createForTextureView(@NonNull CreationOptions options) { + final VideoAsset videoAsset = videoAssetWithOptions(options); + + long id = nextPlayerIdentifier++; + TextureRegistry.SurfaceProducer handle = flutterState.textureRegistry.createSurfaceProducer(); + VideoPlayer videoPlayer = + TextureVideoPlayer.create( + flutterState.applicationContext, + VideoPlayerEventCallbacks.bindTo(createEventChannel(id)), + handle, + videoAsset, + sharedOptions); + + registerPlayerInstance(videoPlayer, id); + return new TexturePlayerIds.Builder().setPlayerId(id).setTextureId(handle.id()).build(); + } + + private @NonNull VideoAsset videoAssetWithOptions(@NonNull CreationOptions options) { + final @NonNull String uri = options.getUri(); if (uri.startsWith("asset:")) { - videoAsset = VideoAsset.fromAssetUrl(uri); + return VideoAsset.fromAssetUrl(uri); } else if (uri.startsWith("rtsp:")) { - videoAsset = VideoAsset.fromRtspUrl(uri); + return VideoAsset.fromRtspUrl(uri); } else { VideoAsset.StreamingFormat streamingFormat = VideoAsset.StreamingFormat.UNKNOWN; - PlatformVideoFormat formatHint = arg.getFormatHint(); + PlatformVideoFormat formatHint = options.getFormatHint(); if (formatHint != null) { switch (formatHint) { case SS: @@ -113,42 +140,20 @@ public void initialize() { break; } } - videoAsset = - VideoAsset.fromRemoteUrl(uri, streamingFormat, arg.getHttpHeaders(), arg.getUserAgent()); - } - - long id; - VideoPlayer videoPlayer; - if (arg.getViewType() == Messages.PlatformVideoViewType.PLATFORM_VIEW) { - id = nextPlatformViewPlayerId--; - videoPlayer = - PlatformViewVideoPlayer.create( - flutterState.applicationContext, - VideoPlayerEventCallbacks.bindTo(createEventChannel(id)), - videoAsset, - options); - } else { - TextureRegistry.SurfaceProducer handle = flutterState.textureRegistry.createSurfaceProducer(); - id = handle.id(); - videoPlayer = - TextureVideoPlayer.create( - flutterState.applicationContext, - VideoPlayerEventCallbacks.bindTo(createEventChannel(id)), - handle, - videoAsset, - options); + return VideoAsset.fromRemoteUrl( + uri, streamingFormat, options.getHttpHeaders(), options.getUserAgent()); } + } + private void registerPlayerInstance(VideoPlayer player, long id) { // Set up the instance-specific API handler, and make sure it is removed when the player is // disposed. BinaryMessenger messenger = flutterState.binaryMessenger; final String channelSuffix = Long.toString(id); - VideoPlayerInstanceApi.setUp(messenger, channelSuffix, videoPlayer); - videoPlayer.setDisposeHandler( - () -> VideoPlayerInstanceApi.setUp(messenger, channelSuffix, null)); + VideoPlayerInstanceApi.setUp(messenger, channelSuffix, player); + player.setDisposeHandler(() -> VideoPlayerInstanceApi.setUp(messenger, channelSuffix, null)); - videoPlayers.put(id, videoPlayer); - return id; + videoPlayers.put(id, player); } @NonNull @@ -182,7 +187,7 @@ public void dispose(@NonNull Long playerId) { @Override public void setMixWithOthers(@NonNull Boolean mixWithOthers) { - options.mixWithOthers = mixWithOthers; + sharedOptions.mixWithOthers = mixWithOthers; } @Override diff --git a/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/VideoPlayerPluginTest.java b/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/VideoPlayerPluginTest.java index ad7d269bead..907d93b3cb1 100644 --- a/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/VideoPlayerPluginTest.java +++ b/packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/VideoPlayerPluginTest.java @@ -11,8 +11,8 @@ import android.util.LongSparseArray; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.platform.PlatformViewRegistry; -import io.flutter.plugins.videoplayer.Messages.CreateMessage; -import io.flutter.plugins.videoplayer.Messages.PlatformVideoViewType; +import io.flutter.plugins.videoplayer.Messages.CreationOptions; +import io.flutter.plugins.videoplayer.Messages.TexturePlayerIds; import io.flutter.plugins.videoplayer.platformview.PlatformVideoViewFactory; import io.flutter.plugins.videoplayer.platformview.PlatformViewVideoPlayer; import io.flutter.plugins.videoplayer.texture.TextureVideoPlayer; @@ -78,17 +78,16 @@ public void createsPlatformViewVideoPlayer() throws Exception { .when(() -> PlatformViewVideoPlayer.create(any(), any(), any(), any())) .thenReturn(mock(PlatformViewVideoPlayer.class)); - final CreateMessage createMessage = - new CreateMessage.Builder() - .setViewType(PlatformVideoViewType.PLATFORM_VIEW) + final CreationOptions options = + new CreationOptions.Builder() .setUri("https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4") .setHttpHeaders(new HashMap<>()) .build(); - final long playerId = plugin.create(createMessage); + final long playerId = plugin.createForPlatformView(options); final LongSparseArray videoPlayers = getVideoPlayers(); - assertNotNull(videoPlayers.get(playerId)); + assertTrue(videoPlayers.get(playerId) instanceof PlatformViewVideoPlayer); } } @@ -100,17 +99,16 @@ public void createsTextureVideoPlayer() throws Exception { .when(() -> TextureVideoPlayer.create(any(), any(), any(), any(), any())) .thenReturn(mock(TextureVideoPlayer.class)); - final CreateMessage createMessage = - new CreateMessage.Builder() - .setViewType(PlatformVideoViewType.TEXTURE_VIEW) + final CreationOptions options = + new CreationOptions.Builder() .setUri("https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4") .setHttpHeaders(new HashMap<>()) .build(); - final long playerId = plugin.create(createMessage); + final TexturePlayerIds ids = plugin.createForTextureView(options); final LongSparseArray videoPlayers = getVideoPlayers(); - assertTrue(videoPlayers.get(playerId) instanceof TextureVideoPlayer); + assertTrue(videoPlayers.get(ids.getPlayerId()) instanceof TextureVideoPlayer); } } } diff --git a/packages/video_player/video_player_android/lib/src/android_video_player.dart b/packages/video_player/video_player_android/lib/src/android_video_player.dart index 015edf16d5d..1e4d27f9935 100644 --- a/packages/video_player/video_player_android/lib/src/android_video_player.dart +++ b/packages/video_player/video_player_android/lib/src/android_video_player.dart @@ -29,14 +29,14 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { AndroidVideoPlayer({ @visibleForTesting AndroidVideoPlayerApi? pluginApi, @visibleForTesting - VideoPlayerInstanceApi Function(int playerId)? playerProvider, + VideoPlayerInstanceApi Function(int playerId)? playerApiProvider, }) : _api = pluginApi ?? AndroidVideoPlayerApi(), - _playerProvider = playerProvider ?? _productionApiProvider; + _playerApiProvider = playerApiProvider ?? _productionApiProvider; final AndroidVideoPlayerApi _api; // A method to create VideoPlayerInstanceApi instances, which can be //overridden for testing. - final VideoPlayerInstanceApi Function(int playerId) _playerProvider; + final VideoPlayerInstanceApi Function(int playerId) _playerApiProvider; final Map _players = {}; @@ -100,16 +100,27 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { if (uri == null) { throw ArgumentError('Unable to construct a video asset from $options'); } - final CreateMessage message = CreateMessage( + final CreationOptions pigeonCreationOptions = CreationOptions( uri: uri, httpHeaders: httpHeaders, userAgent: userAgent, formatHint: formatHint, - viewType: _platformVideoViewTypeFromVideoViewType(options.viewType), ); - final int playerId = await _api.create(message); - ensureApiInitialized(playerId, options.viewType); + final int playerId; + final VideoPlayerViewState state; + switch (options.viewType) { + case VideoViewType.textureView: + final TexturePlayerIds ids = await _api.createForTextureView( + pigeonCreationOptions, + ); + playerId = ids.playerId; + state = VideoPlayerTextureViewState(textureId: ids.textureId); + case VideoViewType.platformView: + playerId = await _api.createForPlatformView(pigeonCreationOptions); + state = const VideoPlayerPlatformViewState(); + } + ensurePlayerInitialized(playerId, state); return playerId; } @@ -130,18 +141,11 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { /// Returns the player instance for [playerId], creating it if it doesn't /// already exist. @visibleForTesting - void ensureApiInitialized(int playerId, VideoViewType viewType) { + void ensurePlayerInitialized(int playerId, VideoPlayerViewState viewState) { _players.putIfAbsent(playerId, () { - final _VideoPlayerViewState viewState = switch (viewType) { - // playerId is also the textureId when using texture view. - VideoViewType.textureView => _VideoPlayerTextureViewState( - textureId: playerId, - ), - VideoViewType.platformView => const _VideoPlayerPlatformViewState(), - }; final String eventChannelName = '$_videoEventChannelNameBase$playerId'; return _PlayerInstance( - _playerProvider(playerId), + _playerApiProvider(playerId), viewState, eventChannelName: eventChannelName, ); @@ -198,13 +202,13 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { @override Widget buildViewWithOptions(VideoViewOptions options) { final int playerId = options.playerId; - final _VideoPlayerViewState viewState = _playerWith(id: playerId).viewState; + final VideoPlayerViewState viewState = _playerWith(id: playerId).viewState; return switch (viewState) { - _VideoPlayerTextureViewState(:final int textureId) => Texture( + VideoPlayerTextureViewState(:final int textureId) => Texture( textureId: textureId, ), - _VideoPlayerPlatformViewState() => PlatformViewPlayer(playerId: playerId), + VideoPlayerPlatformViewState() => PlatformViewPlayer(playerId: playerId), }; } @@ -233,15 +237,6 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { } } -PlatformVideoViewType _platformVideoViewTypeFromVideoViewType( - VideoViewType viewType, -) { - return switch (viewType) { - VideoViewType.textureView => PlatformVideoViewType.textureView, - VideoViewType.platformView => PlatformVideoViewType.platformView, - }; -} - /// An instance of a video player, corresponding to a single player ID in /// [AndroidVideoPlayer]. class _PlayerInstance { @@ -268,7 +263,7 @@ class _PlayerInstance { late final StreamSubscription _eventSubscription; int _lastBufferPosition = -1; - final _VideoPlayerViewState viewState; + final VideoPlayerViewState viewState; Future setLooping(bool looping) { return _api.setLooping(looping); @@ -367,22 +362,25 @@ class _PlayerInstance { } /// Base class representing the state of a video player view. +@visibleForTesting @immutable -sealed class _VideoPlayerViewState { - const _VideoPlayerViewState(); +sealed class VideoPlayerViewState { + const VideoPlayerViewState(); } /// Represents the state of a video player view that uses a texture. -final class _VideoPlayerTextureViewState extends _VideoPlayerViewState { - /// Creates a new instance of [_VideoPlayerTextureViewState]. - const _VideoPlayerTextureViewState({required this.textureId}); +@visibleForTesting +final class VideoPlayerTextureViewState extends VideoPlayerViewState { + /// Creates a new instance of [VideoPlayerTextureViewState]. + const VideoPlayerTextureViewState({required this.textureId}); /// The ID of the texture used by the video player. final int textureId; } /// Represents the state of a video player view that uses a platform view. -final class _VideoPlayerPlatformViewState extends _VideoPlayerViewState { - /// Creates a new instance of [_VideoPlayerPlatformViewState]. - const _VideoPlayerPlatformViewState(); +@visibleForTesting +final class VideoPlayerPlatformViewState extends VideoPlayerViewState { + /// Creates a new instance of [VideoPlayerPlatformViewState]. + const VideoPlayerPlatformViewState(); } diff --git a/packages/video_player/video_player_android/lib/src/messages.g.dart b/packages/video_player/video_player_android/lib/src/messages.g.dart index c33047f7514..1b79bb0678e 100644 --- a/packages/video_player/video_player_android/lib/src/messages.g.dart +++ b/packages/video_player/video_player_android/lib/src/messages.g.dart @@ -36,9 +36,6 @@ bool _deepEquals(Object? a, Object? b) { return a == b; } -/// Pigeon equivalent of VideoViewType. -enum PlatformVideoViewType { textureView, platformView } - /// Pigeon equivalent of video_platform_interface's VideoFormat. enum PlatformVideoFormat { dash, hls, ss } @@ -79,13 +76,12 @@ class PlatformVideoViewCreationParams { int get hashCode => Object.hashAll(_toList()); } -class CreateMessage { - CreateMessage({ +class CreationOptions { + CreationOptions({ required this.uri, this.formatHint, required this.httpHeaders, this.userAgent, - this.viewType, }); String uri; @@ -96,32 +92,69 @@ class CreateMessage { String? userAgent; - PlatformVideoViewType? viewType; - List _toList() { - return [uri, formatHint, httpHeaders, userAgent, viewType]; + return [uri, formatHint, httpHeaders, userAgent]; } Object encode() { return _toList(); } - static CreateMessage decode(Object result) { + static CreationOptions decode(Object result) { result as List; - return CreateMessage( + return CreationOptions( uri: result[0]! as String, formatHint: result[1] as PlatformVideoFormat?, httpHeaders: (result[2] as Map?)!.cast(), userAgent: result[3] as String?, - viewType: result[4] as PlatformVideoViewType?, ); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object other) { - if (other is! CreateMessage || other.runtimeType != runtimeType) { + if (other is! CreationOptions || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class TexturePlayerIds { + TexturePlayerIds({required this.playerId, required this.textureId}); + + int playerId; + + int textureId; + + List _toList() { + return [playerId, textureId]; + } + + Object encode() { + return _toList(); + } + + static TexturePlayerIds decode(Object result) { + result as List; + return TexturePlayerIds( + playerId: result[0]! as int, + textureId: result[1]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! TexturePlayerIds || other.runtimeType != runtimeType) { return false; } if (identical(this, other)) { @@ -184,16 +217,16 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is PlatformVideoViewType) { - buffer.putUint8(129); - writeValue(buffer, value.index); } else if (value is PlatformVideoFormat) { - buffer.putUint8(130); + buffer.putUint8(129); writeValue(buffer, value.index); } else if (value is PlatformVideoViewCreationParams) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is CreationOptions) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is CreateMessage) { + } else if (value is TexturePlayerIds) { buffer.putUint8(132); writeValue(buffer, value.encode()); } else if (value is PlaybackState) { @@ -208,15 +241,14 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - final int? value = readValue(buffer) as int?; - return value == null ? null : PlatformVideoViewType.values[value]; - case 130: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformVideoFormat.values[value]; - case 131: + case 130: return PlatformVideoViewCreationParams.decode(readValue(buffer)!); + case 131: + return CreationOptions.decode(readValue(buffer)!); case 132: - return CreateMessage.decode(readValue(buffer)!); + return TexturePlayerIds.decode(readValue(buffer)!); case 133: return PlaybackState.decode(readValue(buffer)!); default: @@ -266,9 +298,9 @@ class AndroidVideoPlayerApi { } } - Future create(CreateMessage msg) async { + Future createForPlatformView(CreationOptions options) async { final String pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.create$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.createForPlatformView$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, @@ -276,7 +308,7 @@ class AndroidVideoPlayerApi { binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [msg], + [options], ); final List? pigeonVar_replyList = await pigeonVar_sendFuture as List?; @@ -298,6 +330,38 @@ class AndroidVideoPlayerApi { } } + Future createForTextureView(CreationOptions options) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.createForTextureView$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [options], + ); + final List? pigeonVar_replyList = + await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as TexturePlayerIds?)!; + } + } + Future dispose(int playerId) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.dispose$pigeonVar_messageChannelSuffix'; diff --git a/packages/video_player/video_player_android/pigeons/messages.dart b/packages/video_player/video_player_android/pigeons/messages.dart index d37d245225a..3762c0703e2 100644 --- a/packages/video_player/video_player_android/pigeons/messages.dart +++ b/packages/video_player/video_player_android/pigeons/messages.dart @@ -13,9 +13,6 @@ import 'package:pigeon/pigeon.dart'; copyrightHeader: 'pigeons/copyright.txt', ), ) -/// Pigeon equivalent of VideoViewType. -enum PlatformVideoViewType { textureView, platformView } - /// Pigeon equivalent of video_platform_interface's VideoFormat. enum PlatformVideoFormat { dash, hls, ss } @@ -26,13 +23,19 @@ class PlatformVideoViewCreationParams { final int playerId; } -class CreateMessage { - CreateMessage({required this.uri, required this.httpHeaders}); +class CreationOptions { + CreationOptions({required this.uri, required this.httpHeaders}); String uri; PlatformVideoFormat? formatHint; Map httpHeaders; String? userAgent; - PlatformVideoViewType? viewType; +} + +class TexturePlayerIds { + TexturePlayerIds({required this.playerId, required this.textureId}); + + final int playerId; + final int textureId; } class PlaybackState { @@ -48,7 +51,11 @@ class PlaybackState { @HostApi() abstract class AndroidVideoPlayerApi { void initialize(); - int create(CreateMessage msg); + // Creates a new player using a platform view for rendering and returns its + // ID. + int createForPlatformView(CreationOptions options); + // Creates a new player using a texture for rendering and returns its IDs. + TexturePlayerIds createForTextureView(CreationOptions options); void dispose(int playerId); void setMixWithOthers(bool mixWithOthers); String getLookupKeyForAsset(String asset, String? packageName); diff --git a/packages/video_player/video_player_android/pubspec.yaml b/packages/video_player/video_player_android/pubspec.yaml index 00129de08bb..ac12f3df83b 100644 --- a/packages/video_player/video_player_android/pubspec.yaml +++ b/packages/video_player/video_player_android/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_android description: Android implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.8.13 +version: 2.8.14 environment: sdk: ^3.7.0 diff --git a/packages/video_player/video_player_android/test/android_video_player_test.dart b/packages/video_player/video_player_android/test/android_video_player_test.dart index 39a5c487d9c..1efa32459b2 100644 --- a/packages/video_player/video_player_android/test/android_video_player_test.dart +++ b/packages/video_player/video_player_android/test/android_video_player_test.dart @@ -22,14 +22,19 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); (AndroidVideoPlayer, MockAndroidVideoPlayerApi, MockVideoPlayerInstanceApi) - setUpMockPlayer({required int playerId}) { + setUpMockPlayer({required int playerId, int? textureId}) { final MockAndroidVideoPlayerApi pluginApi = MockAndroidVideoPlayerApi(); final MockVideoPlayerInstanceApi instanceApi = MockVideoPlayerInstanceApi(); final AndroidVideoPlayer player = AndroidVideoPlayer( pluginApi: pluginApi, - playerProvider: (_) => instanceApi, + playerApiProvider: (_) => instanceApi, + ); + player.ensurePlayerInitialized( + playerId, + textureId == null + ? const VideoPlayerPlatformViewState() + : VideoPlayerTextureViewState(textureId: textureId), ); - player.ensureApiInitialized(playerId, VideoViewType.platformView); return (player, pluginApi, instanceApi); } @@ -66,9 +71,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const String asset = 'someAsset'; const String package = 'somePackage'; @@ -85,10 +92,12 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, 'asset:///$assetKey'); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, 'asset:///$assetKey'); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), @@ -101,9 +110,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const String uri = 'https://example.com'; final int? playerId = await player.create( @@ -114,12 +125,14 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, uri); - expect(createMessage.formatHint, PlatformVideoFormat.dash); - expect(createMessage.httpHeaders, {}); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, uri); + expect(creationOptions.formatHint, PlatformVideoFormat.dash); + expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), @@ -132,8 +145,10 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); const Map headers = { 'Authorization': 'Bearer token', @@ -145,10 +160,12 @@ void main() { httpHeaders: headers, ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.httpHeaders, headers); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.httpHeaders, headers); }); test('create with network sets a default user agent', () async { @@ -156,8 +173,10 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); await player.create( DataSource( @@ -166,10 +185,12 @@ void main() { httpHeaders: {}, ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.userAgent, 'ExoPlayer'); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.userAgent, 'ExoPlayer'); }); test('create with network uses user agent from headers', () async { @@ -177,8 +198,10 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); const String userAgent = 'Test User Agent'; const Map headers = { @@ -191,10 +214,12 @@ void main() { httpHeaders: headers, ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.userAgent, userAgent); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.userAgent, userAgent); }); test('create with file', () async { @@ -202,17 +227,21 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); const String fileUri = 'file:///foo/bar'; final int? playerId = await player.create( DataSource(sourceType: DataSourceType.file, uri: fileUri), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, fileUri); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, fileUri); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), isA(), @@ -224,8 +253,10 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); const String fileUri = 'file:///foo/bar'; const Map headers = { @@ -238,10 +269,12 @@ void main() { httpHeaders: headers, ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.httpHeaders, headers); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.httpHeaders, headers); }); test('createWithOptions with asset', () async { @@ -249,9 +282,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const String asset = 'someAsset'; const String package = 'somePackage'; @@ -271,10 +306,12 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, 'asset:///$assetKey'); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, 'asset:///$assetKey'); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), @@ -287,9 +324,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const String uri = 'https://example.com'; final int? playerId = await player.createWithOptions( @@ -303,12 +342,14 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, uri); - expect(createMessage.formatHint, PlatformVideoFormat.dash); - expect(createMessage.httpHeaders, {}); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, uri); + expect(creationOptions.formatHint, PlatformVideoFormat.dash); + expect(creationOptions.httpHeaders, {}); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), @@ -321,9 +362,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const Map headers = { 'Authorization': 'Bearer token', @@ -339,10 +382,12 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.httpHeaders, headers); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.httpHeaders, headers); expect(playerId, newPlayerId); }); @@ -351,9 +396,11 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); + ) = setUpMockPlayer(playerId: 1, textureId: 100); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForTextureView(any)).thenAnswer( + (_) async => TexturePlayerIds(playerId: newPlayerId, textureId: 100), + ); const String fileUri = 'file:///foo/bar'; final int? playerId = await player.createWithOptions( @@ -363,10 +410,12 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.uri, fileUri); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, fileUri); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), @@ -379,8 +428,10 @@ void main() { AndroidVideoPlayer player, MockAndroidVideoPlayerApi api, _, - ) = setUpMockPlayer(playerId: 1); - when(api.create(any)).thenAnswer((_) async => 2); + ) = setUpMockPlayer(playerId: 1, textureId: 100); + when( + api.createForTextureView(any), + ).thenAnswer((_) async => TexturePlayerIds(playerId: 2, textureId: 100)); const String fileUri = 'file:///foo/bar'; const Map headers = { @@ -397,10 +448,12 @@ void main() { ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.httpHeaders, headers); + final VerificationResult verification = verify( + api.createForTextureView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.httpHeaders, headers); }); test('createWithOptions with platform view', () async { @@ -410,22 +463,22 @@ void main() { _, ) = setUpMockPlayer(playerId: 1); const int newPlayerId = 2; - when(api.create(any)).thenAnswer((_) async => newPlayerId); + when(api.createForPlatformView(any)).thenAnswer((_) async => newPlayerId); + const String uri = 'file:///foo/bar'; final int? playerId = await player.createWithOptions( VideoCreationOptions( - dataSource: DataSource( - sourceType: DataSourceType.file, - uri: 'file:///foo/bar', - ), + dataSource: DataSource(sourceType: DataSourceType.file, uri: uri), viewType: VideoViewType.platformView, ), ); - final VerificationResult verification = verify(api.create(captureAny)); - final CreateMessage createMessage = - verification.captured[0] as CreateMessage; - expect(createMessage.viewType, PlatformVideoViewType.platformView); + final VerificationResult verification = verify( + api.createForPlatformView(captureAny), + ); + final CreationOptions creationOptions = + verification.captured[0] as CreationOptions; + expect(creationOptions.uri, uri); expect(playerId, newPlayerId); expect( player.buildViewWithOptions(VideoViewOptions(playerId: playerId!)), diff --git a/packages/video_player/video_player_android/test/android_video_player_test.mocks.dart b/packages/video_player/video_player_android/test/android_video_player_test.mocks.dart index 4d7f49d18de..4bc36448aa4 100644 --- a/packages/video_player/video_player_android/test/android_video_player_test.mocks.dart +++ b/packages/video_player/video_player_android/test/android_video_player_test.mocks.dart @@ -23,8 +23,14 @@ import 'package:video_player_android/src/messages.g.dart' as _i2; // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class -class _FakePlaybackState_0 extends _i1.SmartFake implements _i2.PlaybackState { - _FakePlaybackState_0(Object parent, Invocation parentInvocation) +class _FakeTexturePlayerIds_0 extends _i1.SmartFake + implements _i2.TexturePlayerIds { + _FakeTexturePlayerIds_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlaybackState_1 extends _i1.SmartFake implements _i2.PlaybackState { + _FakePlaybackState_1(Object parent, Invocation parentInvocation) : super(parent, parentInvocation); } @@ -58,14 +64,35 @@ class MockAndroidVideoPlayerApi extends _i1.Mock as _i4.Future); @override - _i4.Future create(_i2.CreateMessage? msg) => + _i4.Future createForPlatformView(_i2.CreationOptions? options) => (super.noSuchMethod( - Invocation.method(#create, [msg]), + Invocation.method(#createForPlatformView, [options]), returnValue: _i4.Future.value(0), returnValueForMissingStub: _i4.Future.value(0), ) as _i4.Future); + @override + _i4.Future<_i2.TexturePlayerIds> createForTextureView( + _i2.CreationOptions? options, + ) => + (super.noSuchMethod( + Invocation.method(#createForTextureView, [options]), + returnValue: _i4.Future<_i2.TexturePlayerIds>.value( + _FakeTexturePlayerIds_0( + this, + Invocation.method(#createForTextureView, [options]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.TexturePlayerIds>.value( + _FakeTexturePlayerIds_0( + this, + Invocation.method(#createForTextureView, [options]), + ), + ), + ) + as _i4.Future<_i2.TexturePlayerIds>); + @override _i4.Future dispose(int? playerId) => (super.noSuchMethod( @@ -161,18 +188,18 @@ class MockVideoPlayerInstanceApi extends _i1.Mock as _i4.Future); @override - _i4.Future seekTo(int? position) => + _i4.Future pause() => (super.noSuchMethod( - Invocation.method(#seekTo, [position]), + Invocation.method(#pause, []), returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); @override - _i4.Future pause() => + _i4.Future seekTo(int? position) => (super.noSuchMethod( - Invocation.method(#pause, []), + Invocation.method(#seekTo, [position]), returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) @@ -183,13 +210,13 @@ class MockVideoPlayerInstanceApi extends _i1.Mock (super.noSuchMethod( Invocation.method(#getPlaybackState, []), returnValue: _i4.Future<_i2.PlaybackState>.value( - _FakePlaybackState_0( + _FakePlaybackState_1( this, Invocation.method(#getPlaybackState, []), ), ), returnValueForMissingStub: _i4.Future<_i2.PlaybackState>.value( - _FakePlaybackState_0( + _FakePlaybackState_1( this, Invocation.method(#getPlaybackState, []), ),