From 7ae64052fe8b87d544b6b6338fc3b9654f6e1c99 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 31 Aug 2022 09:57:31 -0400 Subject: [PATCH] [video_player] Remove default method channel implementation Eliminates `MethodChannelVideoPlayer`, and instead makes the default a no-op subclass of the interface (i.e., one that throws `UnimplementedError` for everything). This moves the plugin from option 3 to option 2 in https://docs.flutter.dev/go/platform-channels-in-federated-plugins. This implementation is being removed because its use of Pigeon made ongoing maintenance impractical. Since default implementations are intended for backward compatibility with third-party native-only implementations, the platform channel internals of default implementations are considered part of the API surface. Pigeon considers those details implementation details, which means it was impossible to ever update the version of Pigeon used here without breaking changes. This means that fundamentally, Pigeon is not a viable choice for default implementations. The alternative to removing it would be replacing it with a new non-Pigeon method channel implementation, but that would also be a breaking change, defeating the purpose of backward compatibility. This would only benefit new third-party implementations, but new implementations should implement the platform interface rather than using the legacy default implementation. Fixes https://github.com/flutter/flutter/issues/110017 --- .../CHANGELOG.md | 6 +- .../CONTRIBUTING.md | 46 -- .../lib/messages.g.dart | 425 ------------------ .../lib/method_channel_video_player.dart | 171 ------- .../lib/video_player_platform_interface.dart | 11 +- .../pigeons/messages.dart | 63 --- .../pubspec.yaml | 3 +- .../method_channel_video_player_test.dart | 368 --------------- .../test/test.dart | 199 -------- .../video_player_platform_interface_test.dart | 15 + 10 files changed, 27 insertions(+), 1280 deletions(-) delete mode 100644 packages/video_player/video_player_platform_interface/CONTRIBUTING.md delete mode 100644 packages/video_player/video_player_platform_interface/lib/messages.g.dart delete mode 100644 packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart delete mode 100644 packages/video_player/video_player_platform_interface/pigeons/messages.dart delete mode 100644 packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart delete mode 100644 packages/video_player/video_player_platform_interface/test/test.dart create mode 100644 packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 89e3a05b20e4..05cb63835da4 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,5 +1,9 @@ -## NEXT +## 6.0.0 +* **BREAKING CHANGE**: Removes `MethodChannelVideoPlayer`. The default + implementation is now only a placeholder with no functionality; + implementations of `video_player` must include their own `VideoPlayerPlatform` + Dart implementation. * Updates minimum Flutter version to 2.10. * Fixes violations of new analysis option use_named_constants. diff --git a/packages/video_player/video_player_platform_interface/CONTRIBUTING.md b/packages/video_player/video_player_platform_interface/CONTRIBUTING.md deleted file mode 100644 index 4108ae0d0030..000000000000 --- a/packages/video_player/video_player_platform_interface/CONTRIBUTING.md +++ /dev/null @@ -1,46 +0,0 @@ -## Updating pigeon-generated files - -**WARNING**: Because `messages.dart` is part of the public API of this package, -breaking changes in that file are breaking changes for the package. This means -that: -- You should never update the version of Pigeon used for this package unless - making a breaking change to the package for other reasons. -- Because the method channel is a legacy implementation for compatibility with - existing third-party `video_player` implementations, in many cases the best - option may be to simply not implemented new features in - `MethodChannelVideoPlayer`. Breaking changes in this package should never - be made solely to change `MethodChannelVideoPlayer`. - -### Update process - -If you update files in the pigeons/ directory, run the following -command in this directory (ignore the errors you get about -dependencies in the examples directory): - -```bash -flutter pub upgrade -flutter pub run pigeon --dart_null_safety --input pigeons/messages.dart -# git commit your changes so that your working environment is clean -(cd ../../../; ./script/tool_runner.sh format --clang-format=clang-format-7) -``` - -If you update pigeon itself and want to test the changes here, -temporarily update the pubspec.yaml by adding the following to the -`dependency_overrides` section, assuming you have checked out the -`flutter/packages` repo in a sibling directory to the `plugins` repo: - -```yaml - pigeon: - path: - ../../../../packages/packages/pigeon/ -``` - -Then, run the commands above. When you run `pub get` it should warn -you that you're using an override. If you do this, you will need to -publish pigeon before you can land the updates to this package, since -the CI tests run the analysis using latest published version of -pigeon, not your version or the version on `main`. - -In either case, the configuration will be obtained automatically from -the `pigeons/messages.dart` file (see `configurePigeon` at the bottom -of that file). diff --git a/packages/video_player/video_player_platform_interface/lib/messages.g.dart b/packages/video_player/video_player_platform_interface/lib/messages.g.dart deleted file mode 100644 index 831f4e3755d9..000000000000 --- a/packages/video_player/video_player_platform_interface/lib/messages.g.dart +++ /dev/null @@ -1,425 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Autogenerated from Pigeon (v0.1.21), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, cast_nullable_to_non_nullable -// @dart = 2.12 -import 'dart:async'; -import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; - -import 'package:flutter/services.dart'; - -class TextureMessage { - int? textureId; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['textureId'] = textureId; - return pigeonMap; - } - - static TextureMessage decode(Object message) { - final Map pigeonMap = message as Map; - return TextureMessage()..textureId = pigeonMap['textureId'] as int?; - } -} - -class CreateMessage { - String? asset; - String? uri; - String? packageName; - String? formatHint; - Map? httpHeaders; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['asset'] = asset; - pigeonMap['uri'] = uri; - pigeonMap['packageName'] = packageName; - pigeonMap['formatHint'] = formatHint; - pigeonMap['httpHeaders'] = httpHeaders; - return pigeonMap; - } - - static CreateMessage decode(Object message) { - final Map pigeonMap = message as Map; - return CreateMessage() - ..asset = pigeonMap['asset'] as String? - ..uri = pigeonMap['uri'] as String? - ..packageName = pigeonMap['packageName'] as String? - ..formatHint = pigeonMap['formatHint'] as String? - ..httpHeaders = pigeonMap['httpHeaders'] as Map?; - } -} - -class LoopingMessage { - int? textureId; - bool? isLooping; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['textureId'] = textureId; - pigeonMap['isLooping'] = isLooping; - return pigeonMap; - } - - static LoopingMessage decode(Object message) { - final Map pigeonMap = message as Map; - return LoopingMessage() - ..textureId = pigeonMap['textureId'] as int? - ..isLooping = pigeonMap['isLooping'] as bool?; - } -} - -class VolumeMessage { - int? textureId; - double? volume; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['textureId'] = textureId; - pigeonMap['volume'] = volume; - return pigeonMap; - } - - static VolumeMessage decode(Object message) { - final Map pigeonMap = message as Map; - return VolumeMessage() - ..textureId = pigeonMap['textureId'] as int? - ..volume = pigeonMap['volume'] as double?; - } -} - -class PlaybackSpeedMessage { - int? textureId; - double? speed; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['textureId'] = textureId; - pigeonMap['speed'] = speed; - return pigeonMap; - } - - static PlaybackSpeedMessage decode(Object message) { - final Map pigeonMap = message as Map; - return PlaybackSpeedMessage() - ..textureId = pigeonMap['textureId'] as int? - ..speed = pigeonMap['speed'] as double?; - } -} - -class PositionMessage { - int? textureId; - int? position; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['textureId'] = textureId; - pigeonMap['position'] = position; - return pigeonMap; - } - - static PositionMessage decode(Object message) { - final Map pigeonMap = message as Map; - return PositionMessage() - ..textureId = pigeonMap['textureId'] as int? - ..position = pigeonMap['position'] as int?; - } -} - -class MixWithOthersMessage { - bool? mixWithOthers; - - Object encode() { - final Map pigeonMap = {}; - pigeonMap['mixWithOthers'] = mixWithOthers; - return pigeonMap; - } - - static MixWithOthersMessage decode(Object message) { - final Map pigeonMap = message as Map; - return MixWithOthersMessage() - ..mixWithOthers = pigeonMap['mixWithOthers'] as bool?; - } -} - -class VideoPlayerApi { - Future initialize() async { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.initialize', StandardMessageCodec()); - final Map? replyMap = - await channel.send(null) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future create(CreateMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return TextureMessage.decode(replyMap['result']!); - } - } - - Future dispose(TextureMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future setLooping(LoopingMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setLooping', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future setVolume(VolumeMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setVolume', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future setPlaybackSpeed(PlaybackSpeedMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', - StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future play(TextureMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future position(TextureMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return PositionMessage.decode(replyMap['result']!); - } - } - - Future seekTo(PositionMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future pause(TextureMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } - - Future setMixWithOthers(MixWithOthersMessage arg) async { - final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', - StandardMessageCodec()); - final Map? replyMap = - await channel.send(encoded) as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; - throw PlatformException( - code: error['code'] as String, - message: error['message'] as String?, - details: error['details'], - ); - } else { - // noop - } - } -} diff --git a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart b/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart deleted file mode 100644 index 0c2b4b8d6b14..000000000000 --- a/packages/video_player/video_player_platform_interface/lib/method_channel_video_player.dart +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; - -import 'messages.g.dart'; -import 'video_player_platform_interface.dart'; - -/// An implementation of [VideoPlayerPlatform] that uses method channels. -/// -/// This is the default implementation, for compatibility with existing -/// third-party implementations. It is not used by other implementations in -/// this repository. -class MethodChannelVideoPlayer extends VideoPlayerPlatform { - final VideoPlayerApi _api = VideoPlayerApi(); - - @override - Future init() { - return _api.initialize(); - } - - @override - Future dispose(int textureId) { - return _api.dispose(TextureMessage()..textureId = textureId); - } - - @override - Future create(DataSource dataSource) async { - final CreateMessage message = CreateMessage(); - - switch (dataSource.sourceType) { - case DataSourceType.asset: - message.asset = dataSource.asset; - message.packageName = dataSource.package; - break; - case DataSourceType.network: - message.uri = dataSource.uri; - message.formatHint = _videoFormatStringMap[dataSource.formatHint]; - message.httpHeaders = dataSource.httpHeaders; - break; - case DataSourceType.file: - message.uri = dataSource.uri; - break; - case DataSourceType.contentUri: - message.uri = dataSource.uri; - break; - } - - final TextureMessage response = await _api.create(message); - return response.textureId; - } - - @override - Future setLooping(int textureId, bool looping) { - return _api.setLooping(LoopingMessage() - ..textureId = textureId - ..isLooping = looping); - } - - @override - Future play(int textureId) { - return _api.play(TextureMessage()..textureId = textureId); - } - - @override - Future pause(int textureId) { - return _api.pause(TextureMessage()..textureId = textureId); - } - - @override - Future setVolume(int textureId, double volume) { - return _api.setVolume(VolumeMessage() - ..textureId = textureId - ..volume = volume); - } - - @override - Future setPlaybackSpeed(int textureId, double speed) { - assert(speed > 0); - - return _api.setPlaybackSpeed(PlaybackSpeedMessage() - ..textureId = textureId - ..speed = speed); - } - - @override - Future seekTo(int textureId, Duration position) { - return _api.seekTo(PositionMessage() - ..textureId = textureId - ..position = position.inMilliseconds); - } - - @override - Future getPosition(int textureId) async { - final PositionMessage response = - await _api.position(TextureMessage()..textureId = textureId); - return Duration(milliseconds: response.position!); - } - - @override - Stream videoEventsFor(int textureId) { - return _eventChannelFor(textureId) - .receiveBroadcastStream() - .map((dynamic event) { - final Map map = event as Map; - switch (map['event']) { - case 'initialized': - return VideoEvent( - eventType: VideoEventType.initialized, - duration: Duration(milliseconds: map['duration']! as int), - size: Size((map['width'] as num?)?.toDouble() ?? 0.0, - (map['height'] as num?)?.toDouble() ?? 0.0), - rotationCorrection: map['rotationCorrection'] as int? ?? 0, - ); - case 'completed': - return VideoEvent( - eventType: VideoEventType.completed, - ); - case 'bufferingUpdate': - final List values = map['values']! as List; - - return VideoEvent( - buffered: values.map(_toDurationRange).toList(), - eventType: VideoEventType.bufferingUpdate, - ); - case 'bufferingStart': - return VideoEvent(eventType: VideoEventType.bufferingStart); - case 'bufferingEnd': - return VideoEvent(eventType: VideoEventType.bufferingEnd); - default: - return VideoEvent(eventType: VideoEventType.unknown); - } - }); - } - - @override - Widget buildView(int textureId) { - return Texture(textureId: textureId); - } - - @override - Future setMixWithOthers(bool mixWithOthers) { - return _api.setMixWithOthers( - MixWithOthersMessage()..mixWithOthers = mixWithOthers, - ); - } - - EventChannel _eventChannelFor(int textureId) { - return EventChannel('flutter.io/videoPlayer/videoEvents$textureId'); - } - - static const Map _videoFormatStringMap = - { - VideoFormat.ss: 'ss', - VideoFormat.hls: 'hls', - VideoFormat.dash: 'dash', - VideoFormat.other: 'other', - }; - - DurationRange _toDurationRange(dynamic value) { - final List pair = value as List; - return DurationRange( - Duration(milliseconds: pair[0]! as int), - Duration(milliseconds: pair[1]! as int), - ); - } -} diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 78173f1fb63c..92099eb6635a 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -6,8 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'method_channel_video_player.dart'; - /// The interface that implementations of video_player must implement. /// /// Platform implementations should extend this class rather than implement it as `video_player` @@ -21,11 +19,12 @@ abstract class VideoPlayerPlatform extends PlatformInterface { static final Object _token = Object(); - static VideoPlayerPlatform _instance = MethodChannelVideoPlayer(); + static VideoPlayerPlatform _instance = _PlaceholderImplementation(); - /// The default instance of [VideoPlayerPlatform] to use. + /// The instance of [VideoPlayerPlatform] to use. /// - /// Defaults to [MethodChannelVideoPlayer]. + /// Defaults to a placeholder that does not override any methods, and thus + /// throws `UnimplementedError` in most cases. static VideoPlayerPlatform get instance => _instance; /// Platform-specific plugins should override this with their own @@ -105,6 +104,8 @@ abstract class VideoPlayerPlatform extends PlatformInterface { } } +class _PlaceholderImplementation extends VideoPlayerPlatform {} + /// Description of the data source used to create an instance of /// the video player. class DataSource { diff --git a/packages/video_player/video_player_platform_interface/pigeons/messages.dart b/packages/video_player/video_player_platform_interface/pigeons/messages.dart deleted file mode 100644 index 7a3490a955d4..000000000000 --- a/packages/video_player/video_player_platform_interface/pigeons/messages.dart +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// @dart = 2.9 - -import 'package:pigeon/pigeon_lib.dart'; - -class TextureMessage { - int textureId; -} - -class LoopingMessage { - int textureId; - bool isLooping; -} - -class VolumeMessage { - int textureId; - double volume; -} - -class PlaybackSpeedMessage { - int textureId; - double speed; -} - -class PositionMessage { - int textureId; - int position; -} - -class CreateMessage { - String asset; - String uri; - String packageName; - String formatHint; - Map httpHeaders; -} - -class MixWithOthersMessage { - bool mixWithOthers; -} - -@HostApi(dartHostTestHandler: 'TestHostVideoPlayerApi') -abstract class VideoPlayerApi { - void initialize(); - TextureMessage create(CreateMessage msg); - void dispose(TextureMessage msg); - void setLooping(LoopingMessage msg); - void setVolume(VolumeMessage msg); - void setPlaybackSpeed(PlaybackSpeedMessage msg); - void play(TextureMessage msg); - PositionMessage position(TextureMessage msg); - void seekTo(PositionMessage msg); - void pause(TextureMessage msg); - void setMixWithOthers(MixWithOthersMessage msg); -} - -void configurePigeon(PigeonOptions opts) { - opts.dartOut = 'lib/messages.g.dart'; - opts.dartTestOut = 'test/test.dart'; -} diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index 965641d2ee75..56e132dbb3a7 100644 --- a/packages/video_player/video_player_platform_interface/pubspec.yaml +++ b/packages/video_player/video_player_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/main/packages/video_player/v issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 5.1.4 +version: 6.0.0 environment: sdk: ">=2.12.0 <3.0.0" @@ -18,4 +18,3 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pigeon: 0.1.21 diff --git a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart b/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart deleted file mode 100644 index 7d64ac8ab7d7..000000000000 --- a/packages/video_player/video_player_platform_interface/test/method_channel_video_player_test.dart +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#106316) -// ignore: unnecessary_import -import 'dart:ui'; - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:video_player_platform_interface/messages.g.dart'; -import 'package:video_player_platform_interface/method_channel_video_player.dart'; -import 'package:video_player_platform_interface/video_player_platform_interface.dart'; - -import 'test.dart'; - -class _ApiLogger implements TestHostVideoPlayerApi { - final List log = []; - TextureMessage? textureMessage; - CreateMessage? createMessage; - PositionMessage? positionMessage; - LoopingMessage? loopingMessage; - VolumeMessage? volumeMessage; - PlaybackSpeedMessage? playbackSpeedMessage; - MixWithOthersMessage? mixWithOthersMessage; - - @override - TextureMessage create(CreateMessage arg) { - log.add('create'); - createMessage = arg; - return TextureMessage()..textureId = 3; - } - - @override - void dispose(TextureMessage arg) { - log.add('dispose'); - textureMessage = arg; - } - - @override - void initialize() { - log.add('init'); - } - - @override - void pause(TextureMessage arg) { - log.add('pause'); - textureMessage = arg; - } - - @override - void play(TextureMessage arg) { - log.add('play'); - textureMessage = arg; - } - - @override - void setMixWithOthers(MixWithOthersMessage arg) { - log.add('setMixWithOthers'); - mixWithOthersMessage = arg; - } - - @override - PositionMessage position(TextureMessage arg) { - log.add('position'); - textureMessage = arg; - return PositionMessage()..position = 234; - } - - @override - void seekTo(PositionMessage arg) { - log.add('seekTo'); - positionMessage = arg; - } - - @override - void setLooping(LoopingMessage arg) { - log.add('setLooping'); - loopingMessage = arg; - } - - @override - void setVolume(VolumeMessage arg) { - log.add('setVolume'); - volumeMessage = arg; - } - - @override - void setPlaybackSpeed(PlaybackSpeedMessage arg) { - log.add('setPlaybackSpeed'); - playbackSpeedMessage = arg; - } -} - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - // Store the initial instance before any tests change it. - final VideoPlayerPlatform initialInstance = VideoPlayerPlatform.instance; - - group('$VideoPlayerPlatform', () { - test('$MethodChannelVideoPlayer() is the default instance', () { - expect(initialInstance, isInstanceOf()); - }); - }); - - group('$MethodChannelVideoPlayer', () { - final MethodChannelVideoPlayer player = MethodChannelVideoPlayer(); - late _ApiLogger log; - - setUp(() { - log = _ApiLogger(); - TestHostVideoPlayerApi.setup(log); - }); - - test('init', () async { - await player.init(); - expect( - log.log.last, - 'init', - ); - }); - - test('dispose', () async { - await player.dispose(1); - expect(log.log.last, 'dispose'); - expect(log.textureMessage?.textureId, 1); - }); - - test('create with asset', () async { - final int? textureId = await player.create(DataSource( - sourceType: DataSourceType.asset, - asset: 'someAsset', - package: 'somePackage', - )); - expect(log.log.last, 'create'); - expect(log.createMessage?.asset, 'someAsset'); - expect(log.createMessage?.packageName, 'somePackage'); - expect(textureId, 3); - }); - - test('create with network', () async { - final int? textureId = await player.create(DataSource( - sourceType: DataSourceType.network, - uri: 'someUri', - formatHint: VideoFormat.dash, - )); - expect(log.log.last, 'create'); - expect(log.createMessage?.asset, null); - expect(log.createMessage?.uri, 'someUri'); - expect(log.createMessage?.packageName, null); - expect(log.createMessage?.formatHint, 'dash'); - expect(log.createMessage?.httpHeaders, {}); - expect(textureId, 3); - }); - - test('create with network (some headers)', () async { - final int? textureId = await player.create(DataSource( - sourceType: DataSourceType.network, - uri: 'someUri', - httpHeaders: {'Authorization': 'Bearer token'}, - )); - expect(log.log.last, 'create'); - expect(log.createMessage?.asset, null); - expect(log.createMessage?.uri, 'someUri'); - expect(log.createMessage?.packageName, null); - expect(log.createMessage?.formatHint, null); - expect(log.createMessage?.httpHeaders, - {'Authorization': 'Bearer token'}); - expect(textureId, 3); - }); - - test('create with file', () async { - final int? textureId = await player.create(DataSource( - sourceType: DataSourceType.file, - uri: 'someUri', - )); - expect(log.log.last, 'create'); - expect(log.createMessage?.uri, 'someUri'); - expect(textureId, 3); - }); - - test('setLooping', () async { - await player.setLooping(1, true); - expect(log.log.last, 'setLooping'); - expect(log.loopingMessage?.textureId, 1); - expect(log.loopingMessage?.isLooping, true); - }); - - test('play', () async { - await player.play(1); - expect(log.log.last, 'play'); - expect(log.textureMessage?.textureId, 1); - }); - - test('pause', () async { - await player.pause(1); - expect(log.log.last, 'pause'); - expect(log.textureMessage?.textureId, 1); - }); - - test('setMixWithOthers', () async { - await player.setMixWithOthers(true); - expect(log.log.last, 'setMixWithOthers'); - expect(log.mixWithOthersMessage?.mixWithOthers, true); - - await player.setMixWithOthers(false); - expect(log.log.last, 'setMixWithOthers'); - expect(log.mixWithOthersMessage?.mixWithOthers, false); - }); - - test('setVolume', () async { - await player.setVolume(1, 0.7); - expect(log.log.last, 'setVolume'); - expect(log.volumeMessage?.textureId, 1); - expect(log.volumeMessage?.volume, 0.7); - }); - - test('setPlaybackSpeed', () async { - await player.setPlaybackSpeed(1, 1.5); - expect(log.log.last, 'setPlaybackSpeed'); - expect(log.playbackSpeedMessage?.textureId, 1); - expect(log.playbackSpeedMessage?.speed, 1.5); - }); - - test('seekTo', () async { - await player.seekTo(1, const Duration(milliseconds: 12345)); - expect(log.log.last, 'seekTo'); - expect(log.positionMessage?.textureId, 1); - expect(log.positionMessage?.position, 12345); - }); - - test('getPosition', () async { - final Duration position = await player.getPosition(1); - expect(log.log.last, 'position'); - expect(log.textureMessage?.textureId, 1); - expect(position, const Duration(milliseconds: 234)); - }); - - test('videoEventsFor', () async { - _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .setMockMessageHandler( - 'flutter.io/videoPlayer/videoEvents123', - (ByteData? message) async { - final MethodCall methodCall = - const StandardMethodCodec().decodeMethodCall(message); - if (methodCall.method == 'listen') { - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'initialized', - 'duration': 98765, - 'width': 1920, - 'height': 1080, - }), - (ByteData? data) {}); - - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'initialized', - 'duration': 98765, - 'width': 1920, - 'height': 1080, - 'rotationCorrection': 180, - }), - (ByteData? data) {}); - - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'completed', - }), - (ByteData? data) {}); - - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingUpdate', - 'values': >[ - [0, 1234], - [1235, 4000], - ], - }), - (ByteData? data) {}); - - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingStart', - }), - (ByteData? data) {}); - - await _ambiguate(ServicesBinding.instance) - ?.defaultBinaryMessenger - .handlePlatformMessage( - 'flutter.io/videoPlayer/videoEvents123', - const StandardMethodCodec() - .encodeSuccessEnvelope({ - 'event': 'bufferingEnd', - }), - (ByteData? data) {}); - - return const StandardMethodCodec().encodeSuccessEnvelope(null); - } else if (methodCall.method == 'cancel') { - return const StandardMethodCodec().encodeSuccessEnvelope(null); - } else { - fail('Expected listen or cancel'); - } - }, - ); - expect( - player.videoEventsFor(123), - emitsInOrder([ - VideoEvent( - eventType: VideoEventType.initialized, - duration: const Duration(milliseconds: 98765), - size: const Size(1920, 1080), - rotationCorrection: 0, - ), - VideoEvent( - eventType: VideoEventType.initialized, - duration: const Duration(milliseconds: 98765), - size: const Size(1920, 1080), - rotationCorrection: 180, - ), - VideoEvent(eventType: VideoEventType.completed), - VideoEvent( - eventType: VideoEventType.bufferingUpdate, - buffered: [ - DurationRange( - Duration.zero, - const Duration(milliseconds: 1234), - ), - DurationRange( - const Duration(milliseconds: 1235), - const Duration(milliseconds: 4000), - ), - ]), - VideoEvent(eventType: VideoEventType.bufferingStart), - VideoEvent(eventType: VideoEventType.bufferingEnd), - ])); - }); - }); -} - -/// This allows a value of type T or T? to be treated as a value of type T?. -/// -/// We use this so that APIs that have become non-nullable can still be used -/// with `!` and `?` on the stable branch. -// TODO(ianh): Remove this once we roll stable in late 2021. -T? _ambiguate(T? value) => value; diff --git a/packages/video_player/video_player_platform_interface/test/test.dart b/packages/video_player/video_player_platform_interface/test/test.dart deleted file mode 100644 index c696434826a3..000000000000 --- a/packages/video_player/video_player_platform_interface/test/test.dart +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Autogenerated from Pigeon (v0.1.21), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import -// @dart = 2.12 -import 'dart:async'; -import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:video_player_platform_interface/messages.g.dart'; - -abstract class TestHostVideoPlayerApi { - void initialize(); - TextureMessage create(CreateMessage arg); - void dispose(TextureMessage arg); - void setLooping(LoopingMessage arg); - void setVolume(VolumeMessage arg); - void setPlaybackSpeed(PlaybackSpeedMessage arg); - void play(TextureMessage arg); - PositionMessage position(TextureMessage arg); - void seekTo(PositionMessage arg); - void pause(TextureMessage arg); - void setMixWithOthers(MixWithOthersMessage arg); - static void setup(TestHostVideoPlayerApi? api) { - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.initialize', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - // ignore message - api.initialize(); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.create', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.create was null. Expected CreateMessage.'); - final CreateMessage input = CreateMessage.decode(message!); - final TextureMessage output = api.create(input); - return {'result': output.encode()}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.dispose', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.dispose was null. Expected TextureMessage.'); - final TextureMessage input = TextureMessage.decode(message!); - api.dispose(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setLooping', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.setLooping was null. Expected LoopingMessage.'); - final LoopingMessage input = LoopingMessage.decode(message!); - api.setLooping(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setVolume', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.setVolume was null. Expected VolumeMessage.'); - final VolumeMessage input = VolumeMessage.decode(message!); - api.setVolume(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.setPlaybackSpeed was null. Expected PlaybackSpeedMessage.'); - final PlaybackSpeedMessage input = - PlaybackSpeedMessage.decode(message!); - api.setPlaybackSpeed(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.play', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.play was null. Expected TextureMessage.'); - final TextureMessage input = TextureMessage.decode(message!); - api.play(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.position was null. Expected TextureMessage.'); - final TextureMessage input = TextureMessage.decode(message!); - final PositionMessage output = api.position(input); - return {'result': output.encode()}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.seekTo', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.seekTo was null. Expected PositionMessage.'); - final PositionMessage input = PositionMessage.decode(message!); - api.seekTo(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.pause', StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.pause was null. Expected TextureMessage.'); - final TextureMessage input = TextureMessage.decode(message!); - api.pause(input); - return {}; - }); - } - } - { - const BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers', - StandardMessageCodec()); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.VideoPlayerApi.setMixWithOthers was null. Expected MixWithOthersMessage.'); - final MixWithOthersMessage input = - MixWithOthersMessage.decode(message!); - api.setMixWithOthers(input); - return {}; - }); - } - } - } -} diff --git a/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart b/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart new file mode 100644 index 000000000000..8aa7ad9bd3c1 --- /dev/null +++ b/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:video_player_platform_interface/video_player_platform_interface.dart'; + +void main() { + // Store the initial instance before any tests change it. + final VideoPlayerPlatform initialInstance = VideoPlayerPlatform.instance; + + test('default implementation throws uninimpletemented', () async { + await expectLater(() => initialInstance.init(), throwsUnimplementedError); + }); +}