Unverified Commit dcbc694b authored by Maurice Parrish's avatar Maurice Parrish Committed by GitHub

Have AndroidViewController extend PlatformViewController and add support for...

Have AndroidViewController extend PlatformViewController and add support for hybrid platform views (#60320)
parent 462b0ea7
...@@ -15,8 +15,8 @@ class AndroidPlatformView extends StatelessWidget { ...@@ -15,8 +15,8 @@ class AndroidPlatformView extends StatelessWidget {
const AndroidPlatformView({ const AndroidPlatformView({
Key key, Key key,
@required this.viewType, @required this.viewType,
}) : assert(viewType != null), }) : assert(viewType != null),
super(key: key); super(key: key);
/// The unique identifier for the view type to be embedded by this widget. /// The unique identifier for the view type to be embedded by this widget.
/// ///
...@@ -27,61 +27,23 @@ class AndroidPlatformView extends StatelessWidget { ...@@ -27,61 +27,23 @@ class AndroidPlatformView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PlatformViewLink( return PlatformViewLink(
viewType: viewType, viewType: viewType,
onCreatePlatformView: _onCreateAndroidView, surfaceFactory:
surfaceFactory: (BuildContext context, PlatformViewController controller) { (BuildContext context, PlatformViewController controller) {
return PlatformViewSurface( return AndroidViewSurface(
controller: controller, controller: controller as AndroidViewController,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque, hitTestBehavior: PlatformViewHitTestBehavior.opaque,
); );
}, },
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initAndroidView(
id: params.id,
viewType: params.viewType,
layoutDirection: TextDirection.ltr,
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
); );
} }
PlatformViewController _onCreateAndroidView(PlatformViewCreationParams params) {
final _AndroidViewController controller = _AndroidViewController(params.id, viewType);
controller._initialize().then((_) { params.onPlatformViewCreated(params.id); });
return controller;
}
}
// TODO(egarciad): The Android view controller should be defined in the framework.
// https://github.com/flutter/flutter/issues/55904
class _AndroidViewController extends PlatformViewController {
_AndroidViewController(
this.viewId,
this.viewType,
);
@override
final int viewId;
/// The unique identifier for the Android view type to be embedded by this widget.
///
/// A PlatformViewFactory for this type must have been registered.
final String viewType;
bool _initialized = false;
Future<void> _initialize() async {
// TODO(egarciad): Initialize platform view.
_initialized = true;
}
@override
void clearFocus() {
// TODO(egarciad): Implement clear focus.
}
@override
void dispatchPointerEvent(PointerEvent event) {
// TODO(egarciad): Implement dispatchPointerEvent
}
@override
void dispose() {
if (_initialized) {
// TODO(egarciad): Dispose the android view.
}
}
} }
...@@ -90,7 +90,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin { ...@@ -90,7 +90,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
assert(hitTestBehavior != null), assert(hitTestBehavior != null),
assert(gestureRecognizers != null), assert(gestureRecognizers != null),
_viewController = viewController { _viewController = viewController {
_motionEventsDispatcher = _MotionEventsDispatcher(globalToLocal, viewController); _viewController.pointTransformer = (Offset offset) => globalToLocal(offset);
updateGestureRecognizers(gestureRecognizers); updateGestureRecognizers(gestureRecognizers);
_viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated); _viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated);
this.hitTestBehavior = hitTestBehavior; this.hitTestBehavior = hitTestBehavior;
...@@ -139,7 +139,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin { ...@@ -139,7 +139,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
/// Any active gesture arena the Android view participates in is rejected when the /// Any active gesture arena the Android view participates in is rejected when the
/// set of gesture recognizers is changed. /// set of gesture recognizers is changed.
void updateGestureRecognizers(Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers) { void updateGestureRecognizers(Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers) {
_updateGestureRecognizersWithCallBack(gestureRecognizers, _motionEventsDispatcher.handlePointerEvent); _updateGestureRecognizersWithCallBack(gestureRecognizers, _viewController.dispatchPointerEvent);
} }
@override @override
...@@ -151,8 +151,6 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin { ...@@ -151,8 +151,6 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
@override @override
bool get isRepaintBoundary => true; bool get isRepaintBoundary => true;
_MotionEventsDispatcher _motionEventsDispatcher;
@override @override
void performResize() { void performResize() {
size = constraints.biggest; size = constraints.biggest;
...@@ -225,7 +223,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin { ...@@ -225,7 +223,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
config.isSemanticBoundary = true; config.isSemanticBoundary = true;
if (_viewController.isCreated) { if (_viewController.isCreated) {
config.platformViewId = _viewController.id; config.platformViewId = _viewController.viewId;
} }
} }
} }
...@@ -451,7 +449,7 @@ class _UiKitViewGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -451,7 +449,7 @@ class _UiKitViewGestureRecognizer extends OneSequenceGestureRecognizer {
} }
} }
typedef _HandlePointerEvent = void Function(PointerEvent event); typedef _HandlePointerEvent = Future<void> Function(PointerEvent event);
// This recognizer constructs gesture recognizers from a set of gesture recognizer factories // This recognizer constructs gesture recognizers from a set of gesture recognizer factories
// it was give, adds all of them to a gesture arena team with the _PlatformViewGestureRecognizer // it was give, adds all of them to a gesture arena team with the _PlatformViewGestureRecognizer
...@@ -555,144 +553,6 @@ class _PlatformViewGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -555,144 +553,6 @@ class _PlatformViewGestureRecognizer extends OneSequenceGestureRecognizer {
} }
} }
typedef _GlobalToLocal = Offset Function(Offset point);
// Composes a stream of PointerEvent objects into AndroidMotionEvent objects
// and dispatches them to the associated embedded Android view.
class _MotionEventsDispatcher {
_MotionEventsDispatcher(this.globalToLocal, this.viewController);
final Map<int, AndroidPointerCoords> pointerPositions = <int, AndroidPointerCoords>{};
final Map<int, AndroidPointerProperties> pointerProperties = <int, AndroidPointerProperties>{};
final _GlobalToLocal globalToLocal;
final AndroidViewController viewController;
int nextPointerId = 0;
int downTimeMillis;
void handlePointerEvent(PointerEvent event) {
if (event is PointerDownEvent) {
if (nextPointerId == 0)
downTimeMillis = event.timeStamp.inMilliseconds;
pointerProperties[event.pointer] = propertiesFor(event, nextPointerId++);
}
pointerPositions[event.pointer] = coordsFor(event);
dispatchPointerEvent(event);
if (event is PointerUpEvent) {
pointerPositions.remove(event.pointer);
pointerProperties.remove(event.pointer);
if (pointerProperties.isEmpty) {
nextPointerId = 0;
downTimeMillis = null;
}
}
if (event is PointerCancelEvent) {
pointerPositions.clear();
pointerProperties.clear();
nextPointerId = 0;
downTimeMillis = null;
}
}
void dispatchPointerEvent(PointerEvent event) {
final List<int> pointers = pointerPositions.keys.toList();
final int pointerIdx = pointers.indexOf(event.pointer);
final int numPointers = pointers.length;
// This value must match the value in engine's FlutterView.java.
// This flag indicates whether the original Android pointer events were batched together.
const int kPointerDataFlagBatched = 1;
// Android MotionEvent objects can batch information on multiple pointers.
// Flutter breaks these such batched events into multiple PointerEvent objects.
// When there are multiple active pointers we accumulate the information for all pointers
// as we get PointerEvents, and only send it to the embedded Android view when
// we see the last pointer. This way we achieve the same batching as Android.
if (event.platformData == kPointerDataFlagBatched ||
(isSinglePointerAction(event) && pointerIdx < numPointers - 1))
return;
int action;
switch (event.runtimeType) {
case PointerDownEvent:
action = numPointers == 1 ? AndroidViewController.kActionDown
: AndroidViewController.pointerAction(pointerIdx, AndroidViewController.kActionPointerDown);
break;
case PointerUpEvent:
action = numPointers == 1 ? AndroidViewController.kActionUp
: AndroidViewController.pointerAction(pointerIdx, AndroidViewController.kActionPointerUp);
break;
case PointerMoveEvent:
action = AndroidViewController.kActionMove;
break;
case PointerCancelEvent:
action = AndroidViewController.kActionCancel;
break;
default:
return;
}
final AndroidMotionEvent androidMotionEvent = AndroidMotionEvent(
downTime: downTimeMillis,
eventTime: event.timeStamp.inMilliseconds,
action: action,
pointerCount: pointerPositions.length,
pointerProperties: pointers.map<AndroidPointerProperties>((int i) => pointerProperties[i]).toList(),
pointerCoords: pointers.map<AndroidPointerCoords>((int i) => pointerPositions[i]).toList(),
metaState: 0,
buttonState: 0,
xPrecision: 1.0,
yPrecision: 1.0,
deviceId: 0,
edgeFlags: 0,
source: 0,
flags: 0,
);
viewController.sendMotionEvent(androidMotionEvent);
}
AndroidPointerCoords coordsFor(PointerEvent event) {
final Offset position = globalToLocal(event.position);
return AndroidPointerCoords(
orientation: event.orientation,
pressure: event.pressure,
size: event.size,
toolMajor: event.radiusMajor,
toolMinor: event.radiusMinor,
touchMajor: event.radiusMajor,
touchMinor: event.radiusMinor,
x: position.dx,
y: position.dy,
);
}
AndroidPointerProperties propertiesFor(PointerEvent event, int pointerId) {
int toolType = AndroidPointerProperties.kToolTypeUnknown;
switch(event.kind) {
case PointerDeviceKind.touch:
toolType = AndroidPointerProperties.kToolTypeFinger;
break;
case PointerDeviceKind.mouse:
toolType = AndroidPointerProperties.kToolTypeMouse;
break;
case PointerDeviceKind.stylus:
toolType = AndroidPointerProperties.kToolTypeStylus;
break;
case PointerDeviceKind.invertedStylus:
toolType = AndroidPointerProperties.kToolTypeEraser;
break;
case PointerDeviceKind.unknown:
toolType = AndroidPointerProperties.kToolTypeUnknown;
break;
}
return AndroidPointerProperties(id: pointerId, toolType: toolType);
}
bool isSinglePointerAction(PointerEvent event) => event is! PointerDownEvent && event is! PointerUpEvent;
}
/// A render object for embedding a platform view. /// A render object for embedding a platform view.
/// ///
/// [PlatformViewRenderBox] presents a platform view by adding a [PlatformViewLayer] layer, /// [PlatformViewRenderBox] presents a platform view by adding a [PlatformViewLayer] layer,
......
...@@ -398,22 +398,21 @@ class _HtmlElementViewController extends PlatformViewController { ...@@ -398,22 +398,21 @@ class _HtmlElementViewController extends PlatformViewController {
} }
@override @override
void clearFocus() { Future<void> clearFocus() async {
// Currently this does nothing on Flutter Web. // Currently this does nothing on Flutter Web.
// TODO(het): Implement this. See https://github.com/flutter/flutter/issues/39496 // TODO(het): Implement this. See https://github.com/flutter/flutter/issues/39496
} }
@override @override
void dispatchPointerEvent(PointerEvent event) { Future<void> dispatchPointerEvent(PointerEvent event) async {
// We do not dispatch pointer events to HTML views because they may contain // We do not dispatch pointer events to HTML views because they may contain
// cross-origin iframes, which only accept user-generated events. // cross-origin iframes, which only accept user-generated events.
} }
@override @override
void dispose() { Future<void> dispose() async {
if (_initialized) { if (_initialized) {
// Asynchronously dispose this view. await SystemChannels.platform_views.invokeMethod<void>('dispose', viewId);
SystemChannels.platform_views.invokeMethod<void>('dispose', viewId);
} }
} }
} }
...@@ -904,8 +903,9 @@ class _PlatformViewLinkState extends State<PlatformViewLink> { ...@@ -904,8 +903,9 @@ class _PlatformViewLinkState extends State<PlatformViewLink> {
/// Integrates a platform view with Flutter's compositor, touch, and semantics subsystems. /// Integrates a platform view with Flutter's compositor, touch, and semantics subsystems.
/// ///
/// The compositor integration is done by adding a [PlatformViewLayer] to the layer tree. [PlatformViewLayer] /// The compositor integration is done by adding a [PlatformViewLayer] to the layer tree. [PlatformViewSurface]
/// isn't supported on all platforms (e.g on Android platform views are composited using a [TextureLayer]). /// isn't supported on all platforms (e.g on Android platform views can be composited by using a [TextureLayer] or
/// [AndroidViewSurface]).
/// Custom Flutter embedders can support [PlatformViewLayer]s by implementing a SystemCompositor. /// Custom Flutter embedders can support [PlatformViewLayer]s by implementing a SystemCompositor.
/// ///
/// The widget fills all available space, the parent of this object must provide bounded layout /// The widget fills all available space, the parent of this object must provide bounded layout
...@@ -915,7 +915,7 @@ class _PlatformViewLinkState extends State<PlatformViewLink> { ...@@ -915,7 +915,7 @@ class _PlatformViewLinkState extends State<PlatformViewLink> {
/// ///
/// See also: /// See also:
/// ///
/// * [AndroidView] which embeds an Android platform view in the widget hierarchy. /// * [AndroidView] which embeds an Android platform view in the widget hierarchy using a [TextureLayer].
/// * [UIKitView] which embeds an iOS platform view in the widget hierarchy. /// * [UIKitView] which embeds an iOS platform view in the widget hierarchy.
// TODO(amirh): Link to the embedder's system compositor documentation once available. // TODO(amirh): Link to the embedder's system compositor documentation once available.
class PlatformViewSurface extends LeafRenderObjectWidget { class PlatformViewSurface extends LeafRenderObjectWidget {
...@@ -996,3 +996,46 @@ class PlatformViewSurface extends LeafRenderObjectWidget { ...@@ -996,3 +996,46 @@ class PlatformViewSurface extends LeafRenderObjectWidget {
..updateGestureRecognizers(gestureRecognizers); ..updateGestureRecognizers(gestureRecognizers);
} }
} }
/// Integrates an Android view with Flutter's compositor, touch, and semantics subsystems.
///
/// The compositor integration is done by adding a [PlatformViewLayer] to the layer tree. [PlatformViewLayer]
/// isn't supported on all platforms. Custom Flutter embedders can support
/// [PlatformViewLayer]s by implementing a SystemCompositor.
///
/// The widget fills all available space, the parent of this object must provide bounded layout
/// constraints.
///
/// If the associated platform view is not created, the [AndroidViewSurface] does not paint any contents.
///
/// See also:
///
/// * [AndroidView] which embeds an Android platform view in the widget hierarchy using a [TextureLayer].
/// * [UIKitView] which embeds an iOS platform view in the widget hierarchy.
class AndroidViewSurface extends PlatformViewSurface {
/// Construct an `AndroidPlatformViewSurface`.
const AndroidViewSurface({
Key key,
@required AndroidViewController controller,
@required PlatformViewHitTestBehavior hitTestBehavior,
@required Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
}) : assert(controller != null),
assert(hitTestBehavior != null),
assert(gestureRecognizers != null),
super(
key: key,
controller: controller,
hitTestBehavior: hitTestBehavior,
gestureRecognizers: gestureRecognizers);
@override
RenderObject createRenderObject(BuildContext context) {
final PlatformViewRenderBox renderBox =
super.createRenderObject(context) as PlatformViewRenderBox;
(controller as AndroidViewController).pointTransformer =
(Offset position) => renderBox.globalToLocal(position);
return renderBox;
}
}
...@@ -31,7 +31,7 @@ class FakePlatformViewController extends PlatformViewController { ...@@ -31,7 +31,7 @@ class FakePlatformViewController extends PlatformViewController {
int get viewId => _id; int get viewId => _id;
@override @override
void dispatchPointerEvent(PointerEvent event) { Future<void> dispatchPointerEvent(PointerEvent event) async {
dispatchedPointerEvents.add(event); dispatchedPointerEvents.add(event);
} }
...@@ -42,16 +42,92 @@ class FakePlatformViewController extends PlatformViewController { ...@@ -42,16 +42,92 @@ class FakePlatformViewController extends PlatformViewController {
} }
@override @override
void dispose() { Future<void> dispose() async {
disposed = true; disposed = true;
} }
@override @override
void clearFocus() { Future<void> clearFocus() async {
focusCleared = true; focusCleared = true;
} }
} }
class FakeAndroidViewController implements AndroidViewController {
FakeAndroidViewController(this.viewId);
bool disposed = false;
bool focusCleared = false;
bool created = false;
/// Events that are dispatched;
List<PointerEvent> dispatchedPointerEvents = <PointerEvent>[];
@override
final int viewId;
@override
Offset Function(Offset position) pointTransformer;
@override
Future<void> dispatchPointerEvent(PointerEvent event) async {
dispatchedPointerEvents.add(event);
}
void clearTestingVariables() {
dispatchedPointerEvents.clear();
disposed = false;
focusCleared = false;
}
@override
Future<void> dispose() async {
disposed = true;
}
@override
Future<void> clearFocus() async {
focusCleared = true;
}
@override
Future<void> setSize(Size size) {
throw UnimplementedError();
}
@override
int get textureId => throw UnimplementedError();
@override
bool isCreated;
@override
void addOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) =>
throw UnimplementedError();
@override
int get id => throw UnimplementedError();
@override
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
throw UnimplementedError();
}
@override
Future<void> sendMotionEvent(AndroidMotionEvent event) {
throw UnimplementedError();
}
@override
Future<void> setLayoutDirection(TextDirection layoutDirection) {
throw UnimplementedError();
}
@override
Future<void> create() async {
created = true;
}
}
class FakeAndroidPlatformViewsController { class FakeAndroidPlatformViewsController {
FakeAndroidPlatformViewsController() { FakeAndroidPlatformViewsController() {
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall); SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
...@@ -108,6 +184,7 @@ class FakeAndroidPlatformViewsController { ...@@ -108,6 +184,7 @@ class FakeAndroidPlatformViewsController {
final double width = args['width'] as double; final double width = args['width'] as double;
final double height = args['height'] as double; final double height = args['height'] as double;
final int layoutDirection = args['direction'] as int; final int layoutDirection = args['direction'] as int;
final bool hybrid = args['hybrid'] as bool;
final Uint8List creationParams = args['params'] as Uint8List; final Uint8List creationParams = args['params'] as Uint8List;
if (_views.containsKey(id)) if (_views.containsKey(id))
...@@ -126,13 +203,23 @@ class FakeAndroidPlatformViewsController { ...@@ -126,13 +203,23 @@ class FakeAndroidPlatformViewsController {
await createCompleter.future; await createCompleter.future;
} }
_views[id] = FakeAndroidPlatformView(id, viewType, Size(width, height), layoutDirection, creationParams); _views[id] = FakeAndroidPlatformView(id, viewType,
width != null || height != null ? Size(width, height) : null,
layoutDirection,
hybrid,
creationParams,
);
final int textureId = _textureCounter++; final int textureId = _textureCounter++;
return Future<int>.sync(() => textureId); return Future<int>.sync(() => textureId);
} }
Future<dynamic> _dispose(MethodCall call) { Future<dynamic> _dispose(MethodCall call) {
final int id = call.arguments as int; int id;
if (call.arguments is int) {
id = call.arguments as int;
} else if (call.arguments is Map && call.arguments['hybrid'] == true) {
id = call.arguments['id'] as int;
}
if (!_views.containsKey(id)) if (!_views.containsKey(id))
throw PlatformException( throw PlatformException(
...@@ -381,19 +468,21 @@ class FakeHtmlPlatformViewsController { ...@@ -381,19 +468,21 @@ class FakeHtmlPlatformViewsController {
@immutable @immutable
class FakeAndroidPlatformView { class FakeAndroidPlatformView {
const FakeAndroidPlatformView(this.id, this.type, this.size, this.layoutDirection, [this.creationParams]); const FakeAndroidPlatformView(this.id, this.type, this.size, this.layoutDirection, this.hybrid, [this.creationParams]);
final int id; final int id;
final String type; final String type;
final Uint8List creationParams; final Uint8List creationParams;
final Size size; final Size size;
final int layoutDirection; final int layoutDirection;
final bool hybrid;
FakeAndroidPlatformView copyWith({Size size, int layoutDirection}) => FakeAndroidPlatformView( FakeAndroidPlatformView copyWith({Size size, int layoutDirection}) => FakeAndroidPlatformView(
id, id,
type, type,
size ?? this.size, size ?? this.size,
layoutDirection ?? this.layoutDirection, layoutDirection ?? this.layoutDirection,
hybrid,
creationParams, creationParams,
); );
...@@ -406,15 +495,16 @@ class FakeAndroidPlatformView { ...@@ -406,15 +495,16 @@ class FakeAndroidPlatformView {
&& other.type == type && other.type == type
&& listEquals<int>(other.creationParams, creationParams) && listEquals<int>(other.creationParams, creationParams)
&& other.size == size && other.size == size
&& other.hybrid == hybrid
&& other.layoutDirection == layoutDirection; && other.layoutDirection == layoutDirection;
} }
@override @override
int get hashCode => hashValues(id, type, hashList(creationParams), size, layoutDirection); int get hashCode => hashValues(id, type, hashList(creationParams), size, layoutDirection, hybrid);
@override @override
String toString() { String toString() {
return 'FakeAndroidPlatformView(id: $id, type: $type, size: $size, layoutDirection: $layoutDirection, creationParams: $creationParams)'; return 'FakeAndroidPlatformView(id: $id, type: $type, size: $size, layoutDirection: $layoutDirection, hybrid: $hybrid, creationParams: $creationParams)';
} }
} }
......
...@@ -31,6 +31,17 @@ void main() { ...@@ -31,6 +31,17 @@ void main() {
}, },
throwsA(isA<PlatformException>()), throwsA(isA<PlatformException>()),
); );
expect(
() {
return PlatformViewsService.initSurfaceAndroidView(
id: 0,
viewType: 'web',
layoutDirection: TextDirection.ltr,
).create();
},
throwsA(isA<PlatformException>()),
);
}); });
test('create Android views', () async { test('create Android views', () async {
...@@ -39,11 +50,13 @@ void main() { ...@@ -39,11 +50,13 @@ void main() {
.setSize(const Size(100.0, 100.0)); .setSize(const Size(100.0, 100.0));
await PlatformViewsService.initAndroidView( id: 1, viewType: 'webview', layoutDirection: TextDirection.rtl) await PlatformViewsService.initAndroidView( id: 1, viewType: 'webview', layoutDirection: TextDirection.rtl)
.setSize(const Size(200.0, 300.0)); .setSize(const Size(200.0, 300.0));
await PlatformViewsService.initSurfaceAndroidView(id: 2, viewType: 'webview', layoutDirection: TextDirection.rtl).create();
expect( expect(
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr), const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr, null),
const FakeAndroidPlatformView(1, 'webview', Size(200.0, 300.0), AndroidViewController.kAndroidLayoutDirectionRtl), const FakeAndroidPlatformView(1, 'webview', Size(200.0, 300.0), AndroidViewController.kAndroidLayoutDirectionRtl, null),
const FakeAndroidPlatformView(2, 'webview', null, AndroidViewController.kAndroidLayoutDirectionRtl, true),
])); ]));
}); });
...@@ -58,6 +71,16 @@ void main() { ...@@ -58,6 +71,16 @@ void main() {
() => PlatformViewsService.initAndroidView( () => PlatformViewsService.initAndroidView(
id: 0, viewType: 'web', layoutDirection: TextDirection.ltr).setSize(const Size(100.0, 100.0)), id: 0, viewType: 'web', layoutDirection: TextDirection.ltr).setSize(const Size(100.0, 100.0)),
throwsA(isA<PlatformException>())); throwsA(isA<PlatformException>()));
await PlatformViewsService.initSurfaceAndroidView(
id: 1,
viewType: 'webview',
layoutDirection: TextDirection.ltr,
).create();
expect(
() => PlatformViewsService.initSurfaceAndroidView(
id: 1, viewType: 'web', layoutDirection: TextDirection.ltr).create(),
throwsA(isA<PlatformException>()));
}); });
test('dispose Android view', () async { test('dispose Android view', () async {
...@@ -67,12 +90,16 @@ void main() { ...@@ -67,12 +90,16 @@ void main() {
final AndroidViewController viewController = final AndroidViewController viewController =
PlatformViewsService.initAndroidView(id: 1, viewType: 'webview', layoutDirection: TextDirection.ltr); PlatformViewsService.initAndroidView(id: 1, viewType: 'webview', layoutDirection: TextDirection.ltr);
await viewController.setSize(const Size(200.0, 300.0)); await viewController.setSize(const Size(200.0, 300.0));
await viewController.dispose(); await viewController.dispose();
final AndroidViewController surfaceViewController = PlatformViewsService.initSurfaceAndroidView(id: 1, viewType: 'webview', layoutDirection: TextDirection.ltr);
await surfaceViewController.create();
await surfaceViewController.dispose();
expect( expect(
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr), const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr, null),
])); ]));
}); });
...@@ -115,8 +142,8 @@ void main() { ...@@ -115,8 +142,8 @@ void main() {
expect( expect(
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr), const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr, null),
const FakeAndroidPlatformView(1, 'webview', Size(500.0, 500.0), AndroidViewController.kAndroidLayoutDirectionLtr), const FakeAndroidPlatformView(1, 'webview', Size(500.0, 500.0), AndroidViewController.kAndroidLayoutDirectionLtr, null),
])); ]));
}); });
...@@ -156,7 +183,7 @@ void main() { ...@@ -156,7 +183,7 @@ void main() {
expect( expect(
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr), const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionLtr, null),
])); ]));
}); });
...@@ -169,7 +196,7 @@ void main() { ...@@ -169,7 +196,7 @@ void main() {
expect( expect(
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionRtl), const FakeAndroidPlatformView(0, 'webview', Size(100.0, 100.0), AndroidViewController.kAndroidLayoutDirectionRtl, null),
])); ]));
}); });
}); });
......
...@@ -39,7 +39,7 @@ void main() { ...@@ -39,7 +39,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -78,7 +78,7 @@ void main() { ...@@ -78,7 +78,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr, fakeView.creationParams), AndroidViewController.kAndroidLayoutDirectionLtr, null, fakeView.creationParams),
]), ]),
); );
}); });
...@@ -137,7 +137,7 @@ void main() { ...@@ -137,7 +137,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
...@@ -148,7 +148,7 @@ void main() { ...@@ -148,7 +148,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(100.0, 50.0), FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(100.0, 50.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -182,7 +182,7 @@ void main() { ...@@ -182,7 +182,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 2, 'maps', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 2, 'maps', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -246,7 +246,7 @@ void main() { ...@@ -246,7 +246,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'webview', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -471,7 +471,7 @@ void main() { ...@@ -471,7 +471,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionRtl), AndroidViewController.kAndroidLayoutDirectionRtl, null),
]), ]),
); );
...@@ -489,7 +489,7 @@ void main() { ...@@ -489,7 +489,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -515,7 +515,7 @@ void main() { ...@@ -515,7 +515,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionRtl), AndroidViewController.kAndroidLayoutDirectionRtl, null),
]), ]),
); );
...@@ -536,7 +536,7 @@ void main() { ...@@ -536,7 +536,7 @@ void main() {
viewsController.views, viewsController.views,
unorderedEquals(<FakeAndroidPlatformView>[ unorderedEquals(<FakeAndroidPlatformView>[
FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0), FakeAndroidPlatformView(currentViewId + 1, 'maps', const Size(200.0, 100.0),
AndroidViewController.kAndroidLayoutDirectionLtr), AndroidViewController.kAndroidLayoutDirectionLtr, null),
]), ]),
); );
}); });
...@@ -1016,6 +1016,23 @@ void main() { ...@@ -1016,6 +1016,23 @@ void main() {
}); });
}); });
group('AndroidViewSurface', () {
FakeAndroidViewController controller;
setUp(() {
controller = FakeAndroidViewController(0);
});
testWidgets('AndroidViewSurface sets pointTransformer of view controller', (WidgetTester tester) async {
final AndroidViewSurface surface = AndroidViewSurface(
controller: controller,
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},);
await tester.pumpWidget(surface);
expect(controller.pointTransformer, isNotNull);
});
});
group('UiKitView', () { group('UiKitView', () {
testWidgets('Create UIView', (WidgetTester tester) async { testWidgets('Create UIView', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment