From 88ce9564c3b2fe0143d907793ff3dfccc557615f Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 12 May 2025 11:53:16 -0700 Subject: [PATCH] Error when trying to use old HC mode when HCPP is enabled (#168027) Fixes https://github.com/flutter/flutter/issues/164218. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Gray Mackall --- .../lib/hcpp/hc_errors_with_hcpp_enabled.dart | 152 ++++++++++++++++++ ...llback_to_hc_errors_with_hcpp_enabled.dart | 152 ++++++++++++++++++ .../hc_errors_with_hcpp_enabled_test.dart | 51 ++++++ ...k_to_hc_errors_with_hcpp_enabled_test.dart | 51 ++++++ .../embedding/engine/FlutterEngine.java | 2 + .../platform/PlatformViewsController.java | 22 ++- .../platform/PlatformViewsControllerTest.java | 38 +++++ 7 files changed, 465 insertions(+), 3 deletions(-) create mode 100644 dev/integration_tests/android_engine_test/lib/hcpp/hc_errors_with_hcpp_enabled.dart create mode 100644 dev/integration_tests/android_engine_test/lib/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled.dart create mode 100644 dev/integration_tests/android_engine_test/test_driver/hcpp/hc_errors_with_hcpp_enabled_test.dart create mode 100644 dev/integration_tests/android_engine_test/test_driver/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled_test.dart diff --git a/dev/integration_tests/android_engine_test/lib/hcpp/hc_errors_with_hcpp_enabled.dart b/dev/integration_tests/android_engine_test/lib/hcpp/hc_errors_with_hcpp_enabled.dart new file mode 100644 index 00000000000..514002d3f7c --- /dev/null +++ b/dev/integration_tests/android_engine_test/lib/hcpp/hc_errors_with_hcpp_enabled.dart @@ -0,0 +1,152 @@ +// Copyright 2014 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:convert'; +import 'dart:ui'; + +import 'package:android_driver_extensions/extension.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_driver/driver_extension.dart'; + +import '../src/allow_list_devices.dart'; + +String errorText = ''; + +void main() async { + enableFlutterDriverExtension( + handler: (String? command) async { + return json.encode({ + 'supported': await HybridAndroidViewController.checkIfSupported(), + 'checkErrorText': errorText, + }); + }, + commands: [nativeDriverCommands], + ); + + final ErrorCallback? originalPlatformOnError = PlatformDispatcher.instance.onError; + + // Set up a global error handler for unhandled platform messages + // & other async errors. + PlatformDispatcher.instance.onError = (Object error, StackTrace stack) { + final String currentErrorString = error.toString(); + bool handledByThisCallback = false; + + if (error is PlatformException) { + if (currentErrorString.contains('HC++')) { + errorText = currentErrorString; + handledByThisCallback = true; // We've "handled" it by capturing for the test + } + } + + if (handledByThisCallback) { + return true; + } + + // Otherwise invoke the original handler, if it existed. + if (originalPlatformOnError != null) { + return originalPlatformOnError(error, stack); + } + return false; + }; + + ensureAndroidDevice(); + + // Run on full screen. + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); + runApp(const MyApp()); +} + +final class _HybridCompositionAndroidPlatformView extends StatelessWidget { + const _HybridCompositionAndroidPlatformView({required this.viewType}); + + final String viewType; + + @override + Widget build(BuildContext context) { + return PlatformViewLink( + viewType: viewType, + surfaceFactory: (BuildContext context, PlatformViewController controller) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (PlatformViewCreationParams params) { + return PlatformViewsService.initExpensiveAndroidView( + id: params.id, + viewType: viewType, + layoutDirection: TextDirection.ltr, + creationParamsCodec: const StandardMessageCodec(), + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, + ); + } +} + +class LandingPage extends StatelessWidget { + const LandingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Welcome')), + body: Center( + child: ElevatedButton( + key: const ValueKey('LoadHCPlatformView'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + textStyle: const TextStyle(fontSize: 18), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => const PlatformViewDisplayPage(), + ), + ); + }, + child: const Text('Load Platform View'), + ), + ), + ); + } +} + +class PlatformViewDisplayPage extends StatelessWidget { + const PlatformViewDisplayPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Platform View')), + body: const _HybridCompositionAndroidPlatformView( + viewType: 'blue_orange_gradient_platform_view', + ), + ); + } +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Platform View Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + scaffoldBackgroundColor: Colors.white, // Clean background + appBarTheme: const AppBarTheme(backgroundColor: Colors.blue, foregroundColor: Colors.white), + ), + home: const LandingPage(), // Start with the new landing page + ); + } +} diff --git a/dev/integration_tests/android_engine_test/lib/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled.dart b/dev/integration_tests/android_engine_test/lib/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled.dart new file mode 100644 index 00000000000..3628f718294 --- /dev/null +++ b/dev/integration_tests/android_engine_test/lib/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled.dart @@ -0,0 +1,152 @@ +// Copyright 2014 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:convert'; +import 'dart:ui'; + +import 'package:android_driver_extensions/extension.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_driver/driver_extension.dart'; + +import '../src/allow_list_devices.dart'; + +String errorText = ''; + +void main() async { + enableFlutterDriverExtension( + handler: (String? command) async { + return json.encode({ + 'supported': await HybridAndroidViewController.checkIfSupported(), + 'checkErrorText': errorText, + }); + }, + commands: [nativeDriverCommands], + ); + + final ErrorCallback? originalPlatformOnError = PlatformDispatcher.instance.onError; + + // Set up a global error handler for unhandled platform messages + // & other async errors. + PlatformDispatcher.instance.onError = (Object error, StackTrace stack) { + final String currentErrorString = error.toString(); + bool handledByThisCallback = false; + + if (error is PlatformException) { + if (currentErrorString.contains('HC++')) { + errorText = currentErrorString; + handledByThisCallback = true; // We've "handled" it by capturing for the test + } + } + + if (handledByThisCallback) { + return true; + } + + // Otherwise invoke the original handler, if it existed. + if (originalPlatformOnError != null) { + return originalPlatformOnError(error, stack); + } + return false; + }; + + ensureAndroidDevice(); + + // Run on full screen. + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); + runApp(const MyApp()); +} + +final class _TLHCFallbackToHcAndroidPlatformView extends StatelessWidget { + const _TLHCFallbackToHcAndroidPlatformView({required this.viewType}); + + final String viewType; + + @override + Widget build(BuildContext context) { + return PlatformViewLink( + viewType: viewType, + surfaceFactory: (BuildContext context, PlatformViewController controller) { + return AndroidViewSurface( + controller: controller as AndroidViewController, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + onCreatePlatformView: (PlatformViewCreationParams params) { + return PlatformViewsService.initSurfaceAndroidView( + id: params.id, + viewType: viewType, + layoutDirection: TextDirection.ltr, + creationParamsCodec: const StandardMessageCodec(), + ) + ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) + ..create(); + }, + ); + } +} + +class LandingPage extends StatelessWidget { + const LandingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Welcome')), + body: Center( + child: ElevatedButton( + key: const ValueKey('LoadPlatformView'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + textStyle: const TextStyle(fontSize: 18), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => const PlatformViewDisplayPage(), + ), + ); + }, + child: const Text('Load Platform View'), + ), + ), + ); + } +} + +class PlatformViewDisplayPage extends StatelessWidget { + const PlatformViewDisplayPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Platform View')), + body: const _TLHCFallbackToHcAndroidPlatformView( + viewType: 'blue_orange_gradient_surface_view_platform_view', + ), + ); + } +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Platform View Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + scaffoldBackgroundColor: Colors.white, // Clean background + appBarTheme: const AppBarTheme(backgroundColor: Colors.blue, foregroundColor: Colors.white), + ), + home: const LandingPage(), // Start with the new landing page + ); + } +} diff --git a/dev/integration_tests/android_engine_test/test_driver/hcpp/hc_errors_with_hcpp_enabled_test.dart b/dev/integration_tests/android_engine_test/test_driver/hcpp/hc_errors_with_hcpp_enabled_test.dart new file mode 100644 index 00000000000..116c850de96 --- /dev/null +++ b/dev/integration_tests/android_engine_test/test_driver/hcpp/hc_errors_with_hcpp_enabled_test.dart @@ -0,0 +1,51 @@ +// Copyright 2014 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:convert'; + +import 'package:android_driver_extensions/native_driver.dart'; +import 'package:android_driver_extensions/skia_gold.dart'; +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +import '../_luci_skia_gold_prelude.dart'; + +void main() async { + late final FlutterDriver flutterDriver; + late final NativeDriver nativeDriver; + + setUpAll(() async { + if (isLuci) { + await enableSkiaGoldComparator(namePrefix: 'android_engine_test$goldenVariant'); + } + flutterDriver = await FlutterDriver.connect(); + nativeDriver = await AndroidNativeDriver.connect(flutterDriver); + await nativeDriver.configureForScreenshotTesting(); + await flutterDriver.waitUntilFirstFrameRasterized(); + }); + + tearDownAll(() async { + await nativeDriver.close(); + await flutterDriver.close(); + }); + + test('verify that HCPP is supported and enabled', () async { + final Map response = + json.decode(await flutterDriver.requestData('')) as Map; + + expect(response['supported'], true); + }, timeout: Timeout.none); + + test( + 'should get a PlatformException when trying to create HC PV with HCPP enabled', + () async { + await flutterDriver.tap(find.byValueKey('LoadPlatformView')); + final Map response = + json.decode(await flutterDriver.requestData('')) as Map; + + expect(response['checkErrorText'], contains('HC++')); + }, + timeout: Timeout.none, + ); +} diff --git a/dev/integration_tests/android_engine_test/test_driver/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled_test.dart b/dev/integration_tests/android_engine_test/test_driver/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled_test.dart new file mode 100644 index 00000000000..eecb97c31e2 --- /dev/null +++ b/dev/integration_tests/android_engine_test/test_driver/hcpp/tlhc_with_fallback_to_hc_errors_with_hcpp_enabled_test.dart @@ -0,0 +1,51 @@ +// Copyright 2014 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:convert'; + +import 'package:android_driver_extensions/native_driver.dart'; +import 'package:android_driver_extensions/skia_gold.dart'; +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +import '../_luci_skia_gold_prelude.dart'; + +void main() async { + late final FlutterDriver flutterDriver; + late final NativeDriver nativeDriver; + + setUpAll(() async { + if (isLuci) { + await enableSkiaGoldComparator(namePrefix: 'android_engine_test$goldenVariant'); + } + flutterDriver = await FlutterDriver.connect(); + nativeDriver = await AndroidNativeDriver.connect(flutterDriver); + await nativeDriver.configureForScreenshotTesting(); + await flutterDriver.waitUntilFirstFrameRasterized(); + }); + + tearDownAll(() async { + await nativeDriver.close(); + await flutterDriver.close(); + }); + + test('verify that HCPP is supported and enabled', () async { + final Map response = + json.decode(await flutterDriver.requestData('')) as Map; + + expect(response['supported'], true); + }, timeout: Timeout.none); + + test( + 'should get a PlatformException when TLHC pv falls back to HC with HCPP enabled', + () async { + await flutterDriver.tap(find.byValueKey('LoadPlatformView')); + final Map response = + json.decode(await flutterDriver.requestData('')) as Map; + + expect(response['checkErrorText'], contains('HC++')); + }, + timeout: Timeout.none, + ); +} diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 4754fd062c5..9ac94a10502 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -390,6 +390,8 @@ public class FlutterEngine implements ViewUtils.DisplayUpdater { platformViewsController2.setRegistry(platformViewsController.getRegistry()); platformViewsController2.setFlutterJNI(flutterJNI); + platformViewsController.setFlutterJNI(flutterJNI); + flutterJNI.addEngineLifecycleListener(engineLifecycleListener); flutterJNI.setPlatformViewsController(platformViewsController); flutterJNI.setPlatformViewsController2(platformViewsController2); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index 0bcb4e9552f..48dd8d7b342 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -27,6 +27,7 @@ import io.flutter.Log; import io.flutter.embedding.android.AndroidTouchProcessor; import io.flutter.embedding.android.FlutterView; import io.flutter.embedding.android.MotionEventTracker; +import io.flutter.embedding.engine.FlutterJNI; import io.flutter.embedding.engine.FlutterOverlaySurface; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.mutatorsstack.*; @@ -61,7 +62,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega // required to call `View#invalidate()` to notify Flutter about the update. // This isn't ideal, but given all the other limitations it's a reasonable tradeoff. // Related issue: https://github.com/flutter/flutter/issues/103630 - private static Class[] VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY = {SurfaceView.class}; + private static Class[] VIEW_TYPES_REQUIRE_NON_TLHC = {SurfaceView.class}; private final PlatformViewRegistryImpl registry; @@ -73,6 +74,8 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega // The View currently rendering the Flutter UI associated with these platform views. private FlutterView flutterView; + private FlutterJNI flutterJNI = null; + // The texture registry maintaining the textures into which the embedded views will be rendered. @Nullable private TextureRegistry textureRegistry; @@ -163,6 +166,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega // API level 19 is required for `android.graphics.ImageReader`. enforceMinimumAndroidApiVersion(19); ensureValidRequest(request); + throwIfHCPPEnabled(); final PlatformView platformView = createPlatformView(request, false); @@ -210,8 +214,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega // - The API level is <23, due to TLHC implementation API requirements. final boolean supportsTextureLayerMode = Build.VERSION.SDK_INT >= API_LEVELS.API_23 - && !ViewUtils.hasChildViewOfType( - embeddedView, VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY); + && !ViewUtils.hasChildViewOfType(embeddedView, VIEW_TYPES_REQUIRE_NON_TLHC); // Fall back to Hybrid Composition or Virtual Display when necessary, depending on which // fallback mode is requested. @@ -539,6 +542,15 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) { enforceMinimumAndroidApiVersion(19); Log.i(TAG, "Using hybrid composition for platform view: " + request.viewId); + throwIfHCPPEnabled(); + } + + // Throws an exception if HC++ is enabled, as HC mode can not work in combination with HC++. + private void throwIfHCPPEnabled() { + if (flutterJNI.IsSurfaceControlEnabled()) { + throw new IllegalStateException( + "Trying to create a Hybrid Composition view with HC++ enabled."); + } } // Configures the view for Virtual Display mode, returning the associated texture ID. @@ -953,6 +965,10 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega return platformView.getView(); } + public void setFlutterJNI(FlutterJNI flutterJNI) { + this.flutterJNI = flutterJNI; + } + @Override public boolean usesVirtualDisplay(int id) { return vdControllers.containsKey(id); diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java index 92cf6186810..cca4183676e 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java @@ -110,6 +110,7 @@ public class PlatformViewsControllerTest { public void itRemovesPlatformViewBeforeDiposeIsCalled() { PlatformViewsController platformViewsController = new PlatformViewsController(); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Get the platform view registry. PlatformViewRegistry registry = platformViewsController.getRegistry(); @@ -150,6 +151,7 @@ public class PlatformViewsControllerTest { public void itNotifiesPlatformViewsOfEngineAttachmentAndDetachment() { PlatformViewsController platformViewsController = new PlatformViewsController(); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Get the platform view registry. PlatformViewRegistry registry = platformViewsController.getRegistry(); @@ -224,6 +226,7 @@ public class PlatformViewsControllerTest { platformViewsController.attachToView(fakeFlutterView); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); resize(jni, platformViewsController, platformViewId, 10.0, 20.0); @@ -246,6 +249,7 @@ public class PlatformViewsControllerTest { VirtualDisplayController fakeVdController = mock(VirtualDisplayController.class); PlatformViewsController platformViewsController = new PlatformViewsController(); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); platformViewsController.attachToView(fakeFlutterView); @@ -456,6 +460,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -483,6 +489,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -507,6 +515,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -532,6 +541,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -557,6 +568,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -583,6 +595,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -616,6 +629,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -640,6 +654,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -665,6 +680,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -695,6 +711,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -727,6 +744,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -755,6 +773,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -786,6 +805,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -815,6 +836,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); verify(androidView, never()).setLayoutDirection(anyInt()); @@ -850,6 +873,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -889,6 +913,8 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -928,6 +954,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); // Simulate create call from the framework. @@ -964,6 +991,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); jni.onFirstFrame(); @@ -1024,6 +1052,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); jni.onFirstFrame(); @@ -1065,6 +1094,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); final FlutterView flutterView = attach(jni, platformViewsController); @@ -1107,6 +1137,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); jni.onFirstFrame(); @@ -1158,6 +1189,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); final FlutterView flutterView = mock(FlutterView.class); @@ -1196,6 +1228,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); final FlutterView flutterView = mock(FlutterView.class); @@ -1234,6 +1267,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); attach(jni, platformViewsController); final FlutterView flutterView = mock(FlutterView.class); @@ -1277,6 +1311,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); final FlutterView flutterView = attach(jni, platformViewsController); jni.onFirstFrame(); @@ -1323,6 +1358,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); final FlutterView flutterView = attach(jni, platformViewsController); jni.onFirstFrame(); @@ -1370,6 +1406,7 @@ public class PlatformViewsControllerTest { platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); FlutterJNI jni = new FlutterJNI(); + platformViewsController.setFlutterJNI(jni); FlutterView initFlutterView = mock(FlutterView.class); attachToFlutterView(jni, platformViewsController, initFlutterView); @@ -1407,6 +1444,7 @@ public class PlatformViewsControllerTest { final FlutterJNI jni = new FlutterJNI(); jni.attachToNative(); + platformViewsController.setFlutterJNI(jni); final FlutterView flutterView = attach(jni, platformViewsController);