diff --git a/.ci.yaml b/.ci.yaml
index f97120d1b63..3cc18d1c96c 100755
--- a/.ci.yaml
+++ b/.ci.yaml
@@ -2023,6 +2023,7 @@ targets:
- name: Linux_android hybrid_android_views_integration_test
recipe: devicelab/devicelab_drone
presubmit: false
+ bringup: true # https://github.com/flutter/flutter/issues/100991
timeout: 60
properties:
tags: >
diff --git a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
index 0e3e9627e49..63d3eac735e 100644
--- a/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
+++ b/dev/integration_tests/hybrid_android_views/android/app/src/main/AndroidManifest.xml
@@ -16,7 +16,8 @@ found in the LICENSE file. -->
android:launchMode="singleTop"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
- android:windowSoftInputMode="adjustResize">
+ android:windowSoftInputMode="adjustResize"
+ android:exported="true">
@@ -28,9 +29,5 @@ found in the LICENSE file. -->
-
-
diff --git a/dev/integration_tests/hybrid_android_views/lib/android_platform_view.dart b/dev/integration_tests/hybrid_android_views/lib/android_platform_view.dart
index 536497506ec..40630d43339 100644
--- a/dev/integration_tests/hybrid_android_views/lib/android_platform_view.dart
+++ b/dev/integration_tests/hybrid_android_views/lib/android_platform_view.dart
@@ -17,6 +17,7 @@ class AndroidPlatformView extends StatelessWidget {
const AndroidPlatformView({
Key? key,
this.onPlatformViewCreated,
+ this.useHybridComposition = false,
required this.viewType,
}) : assert(viewType != null),
super(key: key);
@@ -31,6 +32,9 @@ class AndroidPlatformView extends StatelessWidget {
/// May be null.
final PlatformViewCreatedCallback? onPlatformViewCreated;
+ // Use hybrid composition.
+ final bool useHybridComposition;
+
@override
Widget build(BuildContext context) {
return PlatformViewLink(
@@ -44,17 +48,27 @@ class AndroidPlatformView extends StatelessWidget {
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
- final AndroidViewController controller =
- PlatformViewsService.initSurfaceAndroidView(
+ print('useHybridComposition=$useHybridComposition');
+ late AndroidViewController controller;
+ if (useHybridComposition) {
+ controller = PlatformViewsService.initExpensiveAndroidView(
id: params.id,
viewType: params.viewType,
layoutDirection: TextDirection.ltr,
- )
- ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated);
+ );
+ } else {
+ controller = PlatformViewsService.initSurfaceAndroidView(
+ id: params.id,
+ viewType: params.viewType,
+ layoutDirection: TextDirection.ltr,
+ );
+ }
if (onPlatformViewCreated != null) {
controller.addOnPlatformViewCreatedListener(onPlatformViewCreated!);
}
- return controller..create();
+ return controller
+ ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
+ ..create();
},
);
}
diff --git a/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart b/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart
index 1c894d2ee2b..b298b0a1c74 100644
--- a/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart
+++ b/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart
@@ -39,6 +39,7 @@ class NestedViewEventBodyState extends State {
int? id;
int nestedViewClickCount = 0;
bool showPlatformView = true;
+ bool useHybridComposition = false;
@override
Widget build(BuildContext context) {
@@ -55,39 +56,63 @@ class NestedViewEventBodyState extends State {
key: const ValueKey('PlatformView'),
viewType: 'simple_view',
onPlatformViewCreated: onPlatformViewCreated,
+ useHybridComposition: useHybridComposition,
) : null,
),
if (_lastTestStatus != _LastTestStatus.pending) _statusWidget(),
if (viewChannel != null) ... [
- ElevatedButton(
- key: const ValueKey('ShowAlertDialog'),
- onPressed: onShowAlertDialogPressed,
- child: const Text('SHOW ALERT DIALOG'),
- ),
- ElevatedButton(
- key: const ValueKey('TogglePlatformView'),
- onPressed: onTogglePlatformView,
- child: const Text('TOGGLE PLATFORM VIEW'),
+ Row(
+ children: [
+ Expanded(
+ child: ElevatedButton(
+ key: const ValueKey('ShowAlertDialog'),
+ onPressed: onShowAlertDialogPressed,
+ child: const Text('SHOW ALERT DIALOG'),
+ ),
+ ),
+ Expanded(
+ child: ElevatedButton(
+ key: const ValueKey('TogglePlatformView'),
+ onPressed: onTogglePlatformView,
+ child: const Text('TOGGLE PLATFORM VIEW'),
+ ),
+ ),
+ ],
),
Row(
children: [
- ElevatedButton(
- key: const ValueKey('AddChildView'),
- onPressed: onChildViewPressed,
- child: const Text('ADD CHILD VIEW'),
- ),
- ElevatedButton(
- key: const ValueKey('TapChildView'),
- onPressed: onTapChildViewPressed,
- child: const Text('TAP CHILD VIEW'),
- ),
- if (nestedViewClickCount > 0)
- Text(
- 'Click count: $nestedViewClickCount',
- key: const ValueKey('NestedViewClickCount'),
+ Expanded(
+ child: ElevatedButton(
+ key: const ValueKey('ToggleHybridComposition'),
+ child: const Text('TOGGLE HC'),
+ onPressed: () {
+ setState(() {
+ useHybridComposition = !useHybridComposition;
+ });
+ },
),
+ ),
+ Expanded(
+ child: ElevatedButton(
+ key: const ValueKey('AddChildView'),
+ onPressed: onChildViewPressed,
+ child: const Text('ADD CHILD VIEW'),
+ ),
+ ),
+ Expanded(
+ child: ElevatedButton(
+ key: const ValueKey('TapChildView'),
+ onPressed: onTapChildViewPressed,
+ child: const Text('TAP CHILD VIEW'),
+ ),
+ ),
],
),
+ if (nestedViewClickCount > 0)
+ Text(
+ 'Click count: $nestedViewClickCount',
+ key: const ValueKey('NestedViewClickCount'),
+ ),
],
],
),
diff --git a/dev/integration_tests/hybrid_android_views/test_driver/main_test.dart b/dev/integration_tests/hybrid_android_views/test_driver/main_test.dart
index 0ad2ff0c5ec..d4c75ed32af 100644
--- a/dev/integration_tests/hybrid_android_views/test_driver/main_test.dart
+++ b/dev/integration_tests/hybrid_android_views/test_driver/main_test.dart
@@ -59,10 +59,58 @@ Future main() async {
}, timeout: Timeout.none);
});
- group('Flutter surface switch', () {
+ group('Flutter surface without hybrid composition', () {
setUpAll(() async {
- final SerializableFinder wmListTile = find.byValueKey('NestedViewEventTile');
- await driver.tap(wmListTile);
+ await driver.tap(find.byValueKey('NestedViewEventTile'));
+ });
+
+ tearDownAll(() async {
+ await driver.waitFor(find.pageBack());
+ await driver.tap(find.pageBack());
+ });
+
+ test('Uses FlutterSurfaceView when Android view is on the screen', () async {
+ await driver.waitFor(find.byValueKey('PlatformView'));
+
+ expect(
+ await driver.requestData('hierarchy'),
+ '|-FlutterView\n'
+ ' |-FlutterSurfaceView\n' // Flutter UI
+ ' |-ViewGroup\n' // Platform View
+ ' |-ViewGroup\n'
+ );
+
+ // Hide platform view.
+ final SerializableFinder togglePlatformView = find.byValueKey('TogglePlatformView');
+ await driver.tap(togglePlatformView);
+ await driver.waitForAbsent(find.byValueKey('PlatformView'));
+
+ expect(
+ await driver.requestData('hierarchy'),
+ '|-FlutterView\n'
+ ' |-FlutterSurfaceView\n' // Just the Flutter UI
+ );
+
+ // Show platform view again.
+ await driver.tap(togglePlatformView);
+ await driver.waitFor(find.byValueKey('PlatformView'));
+
+ expect(
+ await driver.requestData('hierarchy'),
+ '|-FlutterView\n'
+ ' |-FlutterSurfaceView\n' // Flutter UI
+ ' |-ViewGroup\n' // Platform View
+ ' |-ViewGroup\n'
+ );
+ }, timeout: Timeout.none);
+ });
+
+ group('Flutter surface with hybrid composition', () {
+ setUpAll(() async {
+ await driver.tap(find.byValueKey('NestedViewEventTile'));
+ await driver.tap(find.byValueKey('ToggleHybridComposition'));
+ await driver.tap(find.byValueKey('TogglePlatformView'));
+ await driver.tap(find.byValueKey('TogglePlatformView'));
});
tearDownAll(() async {
diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart
index 97a6d4f953f..49972dc53f3 100644
--- a/packages/flutter/lib/src/rendering/platform_view.dart
+++ b/packages/flutter/lib/src/rendering/platform_view.dart
@@ -52,7 +52,7 @@ Set _factoriesTypeSet(Set> factories) {
/// A render object for an Android view.
///
-/// Requires Android API level 20 or greater.
+/// Requires Android API level 23 or greater.
///
/// [RenderAndroidView] is responsible for sizing, displaying and passing touch events to an
/// Android [View](https://developer.android.com/reference/android/view/View).
@@ -74,7 +74,7 @@ Set _factoriesTypeSet(Set> factories) {
///
/// * [AndroidView] which is a widget that is used to show an Android view.
/// * [PlatformViewsService] which is a service for controlling platform views.
-class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
+class RenderAndroidView extends PlatformViewRenderBox {
/// Creates a render object for an Android view.
RenderAndroidView({
required AndroidViewController viewController,
@@ -86,7 +86,8 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
assert(gestureRecognizers != null),
assert(clipBehavior != null),
_viewController = viewController,
- _clipBehavior = clipBehavior {
+ _clipBehavior = clipBehavior,
+ super(controller: viewController, hitTestBehavior: hitTestBehavior, gestureRecognizers: gestureRecognizers) {
_viewController.pointTransformer = (Offset offset) => globalToLocal(offset);
updateGestureRecognizers(gestureRecognizers);
_viewController.addOnPlatformViewCreatedListener(_onPlatformViewCreated);
@@ -101,18 +102,22 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
bool _isDisposed = false;
/// The Android view controller for the Android view associated with this render object.
- AndroidViewController get viewController => _viewController;
+ @override
+ AndroidViewController get controller => _viewController;
+
AndroidViewController _viewController;
+
/// Sets a new Android view controller.
- ///
- /// `viewController` must not be null.
- set viewController(AndroidViewController viewController) {
+ @override
+ set controller(AndroidViewController controller) {
assert(_viewController != null);
- assert(viewController != null);
- if (_viewController == viewController)
+ assert(controller != null);
+ if (_viewController == controller)
return;
_viewController.removeOnPlatformViewCreatedListener(_onPlatformViewCreated);
- _viewController = viewController;
+ super.controller = controller;
+ _viewController = controller;
+ _viewController.pointTransformer = (Offset offset) => globalToLocal(offset);
_sizePlatformView();
if (_viewController.isCreated) {
markNeedsSemanticsUpdate();
@@ -138,26 +143,6 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
markNeedsSemanticsUpdate();
}
- /// {@template flutter.rendering.RenderAndroidView.updateGestureRecognizers}
- /// Updates which gestures should be forwarded to the platform view.
- ///
- /// Gesture recognizers created by factories in this set participate in the gesture arena for each
- /// pointer that was put down on the render box. If any of the recognizers on this list wins the
- /// gesture arena, the entire pointer event sequence starting from the pointer down event
- /// will be dispatched to the Android view.
- ///
- /// The `gestureRecognizers` property must not contain more than one factory with the same [Factory.type].
- ///
- /// Setting a new set of gesture recognizer factories with the same [Factory.type]s as the current
- /// set has no effect, because the factories' constructors would have already been called with the previous set.
- /// {@endtemplate}
- ///
- /// Any active gesture arena the Android view participates in is rejected when the
- /// set of gesture recognizers is changed.
- void updateGestureRecognizers(Set> gestureRecognizers) {
- _updateGestureRecognizersWithCallBack(gestureRecognizers, _viewController.dispatchPointerEvent);
- }
-
@override
bool get sizedByParent => true;
@@ -182,9 +167,8 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
// Android virtual displays cannot have a zero size.
// Trying to size it to 0 crashes the app, which was happening when starting the app
// with a locked screen (see: https://github.com/flutter/flutter/issues/20456).
- if (_state == _PlatformViewState.resizing || size.isEmpty) {
+ if (_state == _PlatformViewState.resizing || size.isEmpty)
return;
- }
_state = _PlatformViewState.resizing;
markNeedsPaint();
@@ -212,7 +196,8 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
void _setOffset() {
SchedulerBinding.instance.addPostFrameCallback((_) async {
if (!_isDisposed) {
- await _viewController.setOffset(localToGlobal(Offset.zero));
+ if (attached)
+ await _viewController.setOffset(localToGlobal(Offset.zero));
// Schedule a new post frame callback.
_setOffset();
}
@@ -221,7 +206,7 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
@override
void paint(PaintingContext context, Offset offset) {
- if (_viewController.textureId == null)
+ if (_viewController.textureId == null || _currentTextureSize == null)
return;
// As resizing the Android view happens asynchronously we don't know exactly when is a
@@ -264,14 +249,15 @@ class RenderAndroidView extends RenderBox with _PlatformViewGestureMixin {
context.addLayer(TextureLayer(
rect: offset & _currentTextureSize!,
- textureId: viewController.textureId!,
+ textureId: _viewController.textureId!,
));
}
@override
- void describeSemanticsConfiguration (SemanticsConfiguration config) {
- super.describeSemanticsConfiguration(config);
-
+ void describeSemanticsConfiguration(SemanticsConfiguration config) {
+ // Don't call the super implementation since `platformViewId` should
+ // be set only when the platform view is created, but the concept of
+ // a "created" platform view belongs to this subclass.
config.isSemanticBoundary = true;
if (_viewController.isCreated) {
@@ -339,7 +325,7 @@ class RenderUiKitView extends RenderBox {
// any newly arriving events there's nothing we need to invalidate.
PlatformViewHitTestBehavior hitTestBehavior;
- /// {@macro flutter.rendering.RenderAndroidView.updateGestureRecognizers}
+ /// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers}
void updateGestureRecognizers(Set> gestureRecognizers) {
assert(gestureRecognizers != null);
assert(
@@ -653,11 +639,11 @@ class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin {
PlatformViewController get controller => _controller;
PlatformViewController _controller;
/// This value must not be null, and setting it to a new value will result in a repaint.
- set controller(PlatformViewController controller) {
+ set controller(covariant PlatformViewController controller) {
assert(controller != null);
assert(controller.viewId != null && controller.viewId > -1);
- if ( _controller == controller) {
+ if (_controller == controller) {
return;
}
final bool needsSemanticsUpdate = _controller.viewId != controller.viewId;
@@ -668,7 +654,19 @@ class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin {
}
}
- /// {@macro flutter.rendering.RenderAndroidView.updateGestureRecognizers}
+ /// {@template flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers}
+ /// Updates which gestures should be forwarded to the platform view.
+ ///
+ /// Gesture recognizers created by factories in this set participate in the gesture arena for each
+ /// pointer that was put down on the render box. If any of the recognizers on this list wins the
+ /// gesture arena, the entire pointer event sequence starting from the pointer down event
+ /// will be dispatched to the Android view.
+ ///
+ /// The `gestureRecognizers` property must not contain more than one factory with the same [Factory.type].
+ ///
+ /// Setting a new set of gesture recognizer factories with the same [Factory.type]s as the current
+ /// set has no effect, because the factories' constructors would have already been called with the previous set.
+ /// {@endtemplate}
///
/// Any active gesture arena the `PlatformView` participates in is rejected when the
/// set of gesture recognizers is changed.
@@ -700,7 +698,7 @@ class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin {
}
@override
- void describeSemanticsConfiguration (SemanticsConfiguration config) {
+ void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
assert(_controller.viewId != null);
config.isSemanticBoundary = true;
diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart
index f1f97a6fb5f..fb4c9ba9ac9 100644
--- a/packages/flutter/lib/src/services/platform_views.dart
+++ b/packages/flutter/lib/src/services/platform_views.dart
@@ -76,10 +76,8 @@ class PlatformViewsService {
/// The callbacks are invoked when the platform view asks to be focused.
final Map _focusCallbacks = {};
-
- /// Creates a [TextureAndroidViewController] for a new Android view.
- ///
- /// The view is created after calling [TextureAndroidViewController.setSize].
+ /// {@template flutter.services.PlatformViewsService.initAndroidView}
+ /// Creates a controller for a new Android view.
///
/// `id` is an unused unique identifier generated with [platformViewsRegistry].
///
@@ -103,7 +101,8 @@ class PlatformViewsService {
///
/// The `id, `viewType, and `layoutDirection` parameters must not be null.
/// If `creationParams` is non null then `creationParamsCodec` must not be null.
- static TextureAndroidViewController initAndroidView({
+ /// {@endtemplate}
+ static AndroidViewController initAndroidView({
required int id,
required String viewType,
required TextDirection layoutDirection,
@@ -128,32 +127,11 @@ class PlatformViewsService {
return controller;
}
- /// Creates a [SurfaceAndroidViewController] for a new Android view.
+ /// {@macro flutter.services.PlatformViewsService.initAndroidView}
///
- /// The view is created after calling [AndroidViewController.create].
- ///
- /// `id` is an unused unique identifier generated with [platformViewsRegistry].
- ///
- /// `viewType` is the identifier of the Android view type to be created, a
- /// factory for this view type must have been registered on the platform side.
- /// Platform view factories are typically registered by plugin code.
- /// Plugins can register a platform view factory with
- /// [PlatformViewRegistry#registerViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewRegistry.html#registerViewFactory-java.lang.String-io.flutter.plugin.platform.PlatformViewFactory-).
- ///
- /// `creationParams` will be passed as the args argument of [PlatformViewFactory#create](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#create-android.content.Context-int-java.lang.Object-)
- ///
- /// `creationParamsCodec` is the codec used to encode `creationParams` before sending it to the
- /// platform side. It should match the codec passed to the constructor of [PlatformViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#PlatformViewFactory-io.flutter.plugin.common.MessageCodec-).
- /// This is typically one of: [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec].
- ///
- /// `onFocus` is a callback that will be invoked when the Android View asks to get the
- /// input focus.
- ///
- /// The Android view will only be created after [AndroidViewController.setSize] is called for the
- /// first time.
- ///
- /// The `id, `viewType, and `layoutDirection` parameters must not be null.
- /// If `creationParams` is non null then `creationParamsCodec` must not be null.
+ /// Alias for [initAndroidView].
+ /// This factory is provided for backward compatibility purposes.
+ /// In the future, this method will be deprecated.
static SurfaceAndroidViewController initSurfaceAndroidView({
required int id,
required String viewType,
@@ -174,28 +152,43 @@ class PlatformViewsService {
creationParams: creationParams,
creationParamsCodec: creationParamsCodec,
);
+ _instance._focusCallbacks[id] = onFocus ?? () {};
+ return controller;
+ }
+
+ /// {@macro flutter.services.PlatformViewsService.initAndroidView}
+ ///
+ /// When this factory is used, the Android view and Flutter widgets are composed at the
+ /// Android view hierarchy level.
+ /// This is only useful if the view is a Android SurfaceView. However, using this method
+ /// has a performance cost on devices that run below 10, or underpowered devices.
+ /// In most situations, you should use [initAndroidView].
+ static ExpensiveAndroidViewController initExpensiveAndroidView({
+ required int id,
+ required String viewType,
+ required TextDirection layoutDirection,
+ dynamic creationParams,
+ MessageCodec? creationParamsCodec,
+ VoidCallback? onFocus,
+ }) {
+ final ExpensiveAndroidViewController controller = ExpensiveAndroidViewController._(
+ viewId: id,
+ viewType: viewType,
+ layoutDirection: layoutDirection,
+ creationParams: creationParams,
+ creationParamsCodec: creationParamsCodec,
+ );
_instance._focusCallbacks[id] = onFocus ?? () {};
return controller;
}
/// Whether the render surface of the Android `FlutterView` should be converted to a `FlutterImageView`.
- ///
- /// When adding platform views using
- /// [Hybrid Composition](https://flutter.dev/docs/development/platform-integration/platform-views),
- /// the engine converts the render surface to a `FlutterImageView` to improve
- /// animation synchronization between Flutter widgets and the Android platform
- /// views. On Android versions < 10, this can have some performance issues.
- /// This flag allows disabling this conversion.
- ///
- /// Defaults to true.
- static Future synchronizeToNativeViewHierarchy(bool yes) {
- assert(defaultTargetPlatform == TargetPlatform.android);
- return SystemChannels.platform_views.invokeMethod(
- 'synchronizeToNativeViewHierarchy',
- yes,
- );
- }
+ @Deprecated(
+ 'No longer necessary to improve performance. '
+ 'This feature was deprecated after v2.11.0-0.1.pre.',
+ )
+ static Future synchronizeToNativeViewHierarchy(bool yes) async {}
// TODO(amirh): reference the iOS plugin API for registering a UIView factory once it lands.
/// This is work in progress, not yet ready to be used, and requires a custom engine build. Creates a controller for a new iOS UIView.
@@ -665,7 +658,7 @@ class _AndroidMotionEventConverter {
event is! PointerDownEvent && event is! PointerUpEvent;
}
-/// Controls an Android view.
+/// Controls an Android view that is composed using a GL texture.
///
/// Typically created with [PlatformViewsService.initAndroidView].
// TODO(bparrishMines): Remove abstract methods that are not required by all subclasses.
@@ -676,7 +669,6 @@ abstract class AndroidViewController extends PlatformViewController {
required TextDirection layoutDirection,
dynamic creationParams,
MessageCodec? creationParamsCodec,
- bool waitingForSize = false,
}) : assert(viewId != null),
assert(viewType != null),
assert(layoutDirection != null),
@@ -684,10 +676,7 @@ abstract class AndroidViewController extends PlatformViewController {
_viewType = viewType,
_layoutDirection = layoutDirection,
_creationParams = creationParams,
- _creationParamsCodec = creationParamsCodec,
- _state = waitingForSize
- ? _AndroidViewState.waitingForSize
- : _AndroidViewState.creating;
+ _creationParamsCodec = creationParamsCodec;
/// Action code for when a primary pointer touched the screen.
///
@@ -737,7 +726,7 @@ abstract class AndroidViewController extends PlatformViewController {
TextDirection _layoutDirection;
- _AndroidViewState _state;
+ _AndroidViewState _state = _AndroidViewState.waitingForSize;
final dynamic _creationParams;
@@ -848,10 +837,16 @@ abstract class AndroidViewController extends PlatformViewController {
/// Removes a callback added with [addOnPlatformViewCreatedListener].
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
+ assert(listener != null);
assert(_state != _AndroidViewState.disposed);
_platformViewCreatedCallbacks.remove(listener);
}
+ /// The created callbacks that are invoked after the platform view has been
+ /// created.
+ @visibleForTesting
+ List get createdCallbacks => _platformViewCreatedCallbacks;
+
/// Sets the layout direction for the Android view.
Future setLayoutDirection(TextDirection layoutDirection) async {
assert(
@@ -938,11 +933,29 @@ abstract class AndroidViewController extends PlatformViewController {
}
}
-/// Controls an Android view by rendering to an [AndroidViewSurface].
-///
-/// Typically created with [PlatformViewsService.initAndroidView].
-class SurfaceAndroidViewController extends AndroidViewController {
- SurfaceAndroidViewController._({
+/// Controls an Android view that is composed using a GL texture.
+/// This controller is created from the [PlatformViewsService.initSurfaceAndroidView] factory,
+/// and is defined for backward compatibility.
+class SurfaceAndroidViewController extends TextureAndroidViewController{
+ SurfaceAndroidViewController._({
+ required int viewId,
+ required String viewType,
+ required TextDirection layoutDirection,
+ dynamic creationParams,
+ MessageCodec? creationParamsCodec,
+ }) : super._(
+ viewId: viewId,
+ viewType: viewType,
+ layoutDirection: layoutDirection,
+ creationParams: creationParams,
+ creationParamsCodec: creationParamsCodec,
+ );
+}
+
+/// Controls an Android view that is composed using the Android view hierarchy.
+/// This controller is created from the [PlatformViewsService.initExpensiveAndroidView] factory.
+class ExpensiveAndroidViewController extends AndroidViewController {
+ ExpensiveAndroidViewController._({
required int viewId,
required String viewType,
required TextDirection layoutDirection,
@@ -1019,7 +1032,6 @@ class TextureAndroidViewController extends AndroidViewController {
layoutDirection: layoutDirection,
creationParams: creationParams,
creationParamsCodec: creationParamsCodec,
- waitingForSize: true,
);
/// The texture entry id into which the Android view is rendered.
@@ -1032,7 +1044,8 @@ class TextureAndroidViewController extends AndroidViewController {
@override
int? get textureId => _textureId;
- late Size _initialSize;
+ /// The size used to create the platform view.
+ Size? _initialSize;
/// The current offset of the platform view.
Offset _off = Offset.zero;
@@ -1047,7 +1060,7 @@ class TextureAndroidViewController extends AndroidViewController {
if (_state == _AndroidViewState.waitingForSize) {
_initialSize = size;
await create();
- return _initialSize;
+ return size;
}
final Map