From ef4ed973cbdc097bfae2998f7f754b368142b050 Mon Sep 17 00:00:00 2001 From: KyleFin <5882840+KyleFin@users.noreply.github.com> Date: Tue, 21 Dec 2021 10:23:06 -0700 Subject: [PATCH] Platform interfaces changes to fix Android rotation https://github.com/flutter/flutter/issues/60327 --- .../CHANGELOG.md | 8 +-- .../lib/method_channel_video_player.dart | 1 + .../lib/video_player_platform_interface.dart | 56 +++++++++++++++---- .../pubspec.yaml | 8 +-- .../method_channel_video_player_test.dart | 24 +++++++- 5 files changed, 73 insertions(+), 24 deletions(-) diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index e0e6a11065ee..c42036511d96 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,10 +1,6 @@ -## 5.0.0 +## 4.2.1 -* **BREAKING CHANGES**: - * Updates to extending `PlatformInterface`. Removes `isMock`, in favor of the - now-standard `MockPlatformInterfaceMixin`. - * Removes test.dart from the public interface. Tests in other packages should - mock `VideoPlatformInterface` rather than the method channel. +* Added rotation on Android for videos recorded in landscapeRight Fixes [#60327](https://github.com/flutter/flutter/issues/60327). ## 4.2.0 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 index e01e5b8c072c..f87ed92b3aa5 100644 --- 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 @@ -111,6 +111,7 @@ class MethodChannelVideoPlayer extends VideoPlayerPlatform { duration: Duration(milliseconds: map['duration']), size: Size(map['width']?.toDouble() ?? 0.0, map['height']?.toDouble() ?? 0.0), + rotationCorrection: map['rotationCorrection']?.toDouble() ?? 0.0, ); case 'completed': return VideoEvent( 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 66b6d709e9fe..ae3c0709f7bf 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 @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; +import 'dart:ui'; + import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:meta/meta.dart' show visibleForTesting; import 'method_channel_video_player.dart'; @@ -15,24 +18,37 @@ import 'method_channel_video_player.dart'; /// (using `extends`) ensures that the subclass will get the default implementation, while /// platform implementations that `implements` this interface will be broken by newly added /// [VideoPlayerPlatform] methods. -abstract class VideoPlayerPlatform extends PlatformInterface { - /// Constructs a VideoPlayerPlatform. - VideoPlayerPlatform() : super(token: _token); - - static final Object _token = Object(); +abstract class VideoPlayerPlatform { + /// Only mock implementations should set this to true. + /// + /// Mockito mocks are implementing this class with `implements` which is forbidden for anything + /// other than mocks (see class docs). This property provides a backdoor for mockito mocks to + /// skip the verification that the class isn't implemented with `implements`. + @visibleForTesting + bool get isMock => false; static VideoPlayerPlatform _instance = MethodChannelVideoPlayer(); /// The default instance of [VideoPlayerPlatform] to use. /// - /// Defaults to [MethodChannelVideoPlayer]. - static VideoPlayerPlatform get instance => _instance; - /// Platform-specific plugins should override this with their own /// platform-specific class that extends [VideoPlayerPlatform] when they /// register themselves. + /// + /// Defaults to [MethodChannelVideoPlayer]. + static VideoPlayerPlatform get instance => _instance; + + // TODO(amirh): Extract common platform interface logic. + // https://github.com/flutter/flutter/issues/43368 static set instance(VideoPlayerPlatform instance) { - PlatformInterface.verifyToken(instance, _token); + if (!instance.isMock) { + try { + instance._verifyProvidesDefaultImplementations(); + } on NoSuchMethodError catch (_) { + throw AssertionError( + 'Platform interfaces must not be implemented with `implements`'); + } + } _instance = instance; } @@ -103,6 +119,14 @@ abstract class VideoPlayerPlatform extends PlatformInterface { Future setMixWithOthers(bool mixWithOthers) { throw UnimplementedError('setMixWithOthers() has not been implemented.'); } + + // This method makes sure that VideoPlayer isn't implemented with `implements`. + // + // See class doc for more details on why implementing this class is forbidden. + // + // This private method is called by the instance setter, which fails if the class is + // implemented with `implements`. + void _verifyProvidesDefaultImplementations() {} } /// Description of the data source used to create an instance of @@ -198,12 +222,13 @@ class VideoEvent { /// /// The [eventType] argument is required. /// - /// Depending on the [eventType], the [duration], [size] and [buffered] - /// arguments can be null. + /// Depending on the [eventType], the [duration], [size], + /// [rotationCorrection], and [buffered] arguments can be null. VideoEvent({ required this.eventType, this.duration, this.size, + this.rotationCorrection, this.buffered, }); @@ -220,6 +245,11 @@ class VideoEvent { /// Only used if [eventType] is [VideoEventType.initialized]. final Size? size; + /// Radians to rotate the video so it is displayed correctly. + /// + /// Only used if [eventType] is [VideoEventType.initialized]. + final double? rotationCorrection; + /// Buffered parts of the video. /// /// Only used if [eventType] is [VideoEventType.bufferingUpdate]. @@ -233,6 +263,7 @@ class VideoEvent { eventType == other.eventType && duration == other.duration && size == other.size && + rotationCorrection == other.rotationCorrection && listEquals(buffered, other.buffered); } @@ -241,6 +272,7 @@ class VideoEvent { eventType.hashCode ^ duration.hashCode ^ size.hashCode ^ + rotationCorrection.hashCode ^ buffered.hashCode; } diff --git a/packages/video_player/video_player_platform_interface/pubspec.yaml b/packages/video_player/video_player_platform_interface/pubspec.yaml index b8404772bffa..79167bf7b233 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/master/packages/video_player 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.0.0 +version: 4.2.1 environment: sdk: ">=2.12.0 <3.0.0" @@ -13,9 +13,9 @@ environment: dependencies: flutter: sdk: flutter - plugin_platform_interface: ^2.0.0 - -dev_dependencies: flutter_test: sdk: flutter + meta: ^1.3.0 + +dev_dependencies: pedantic: ^1.10.0 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 index 4d1c9b78fc34..04a67591c534 100644 --- 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 @@ -8,10 +8,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:video_player_platform_interface/messages.dart'; import 'package:video_player_platform_interface/method_channel_video_player.dart'; +import 'package:video_player_platform_interface/test.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; -import 'test.dart'; - class _ApiLogger implements TestHostVideoPlayerApi { final List log = []; TextureMessage? textureMessage; @@ -256,6 +255,20 @@ void main() { }), (ByteData? data) {}); + await _ambiguate(ServicesBinding.instance) + ?.defaultBinaryMessenger + .handlePlatformMessage( + "flutter.io/videoPlayer/videoEvents123", + const StandardMethodCodec() + .encodeSuccessEnvelope({ + 'event': 'initialized', + 'duration': 98765, + 'width': 1920, + 'height': 1080, + 'rotationCorrection': 3.14, + }), + (ByteData? data) {}); + await _ambiguate(ServicesBinding.instance) ?.defaultBinaryMessenger .handlePlatformMessage( @@ -315,6 +328,13 @@ void main() { eventType: VideoEventType.initialized, duration: const Duration(milliseconds: 98765), size: const Size(1920, 1080), + rotationCorrection: 0.0, + ), + VideoEvent( + eventType: VideoEventType.initialized, + duration: const Duration(milliseconds: 98765), + size: const Size(1920, 1080), + rotationCorrection: 3.14, ), VideoEvent(eventType: VideoEventType.completed), VideoEvent(