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].

<!-- Links -->
[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 <mackall@google.com>
This commit is contained in:
Gray Mackall 2025-05-12 11:53:16 -07:00 committed by GitHub
parent b772c17f0d
commit 88ce9564c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 465 additions and 3 deletions

View File

@ -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(<String, Object?>{
'supported': await HybridAndroidViewController.checkIfSupported(),
'checkErrorText': errorText,
});
},
commands: <CommandExtension>[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 <Factory<OneSequenceGestureRecognizer>>{},
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<String>('LoadHCPlatformView'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
textStyle: const TextStyle(fontSize: 18),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
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
);
}
}

View File

@ -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(<String, Object?>{
'supported': await HybridAndroidViewController.checkIfSupported(),
'checkErrorText': errorText,
});
},
commands: <CommandExtension>[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 <Factory<OneSequenceGestureRecognizer>>{},
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<String>('LoadPlatformView'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
textStyle: const TextStyle(fontSize: 18),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
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
);
}
}

View File

@ -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<String, Object?> response =
json.decode(await flutterDriver.requestData('')) as Map<String, Object?>;
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<String, Object?> response =
json.decode(await flutterDriver.requestData('')) as Map<String, Object?>;
expect(response['checkErrorText'], contains('HC++'));
},
timeout: Timeout.none,
);
}

View File

@ -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<String, Object?> response =
json.decode(await flutterDriver.requestData('')) as Map<String, Object?>;
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<String, Object?> response =
json.decode(await flutterDriver.requestData('')) as Map<String, Object?>;
expect(response['checkErrorText'], contains('HC++'));
},
timeout: Timeout.none,
);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);