diff --git a/testing/scenario_app/android/BUILD.gn b/testing/scenario_app/android/BUILD.gn index 9aabbdc72adaa..8d00892fa5726 100644 --- a/testing/scenario_app/android/BUILD.gn +++ b/testing/scenario_app/android/BUILD.gn @@ -7,7 +7,6 @@ import("//flutter/testing/rules/android.gni") _android_sources = [ "app/build.gradle", "app/src/androidTest/java/dev/flutter/TestRunner.java", - "app/src/androidTest/java/dev/flutter/scenarios/EngineLaunchE2ETest.java", "app/src/androidTest/java/dev/flutter/scenarios/ExampleInstrumentedTest.java", "app/src/androidTest/java/dev/flutter/scenariosui/DrawSolidBlueScreenTest.java", "app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java", diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/TestRunner.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/TestRunner.java index 18962141cca02..ac9b70cce61a5 100644 --- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/TestRunner.java +++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/TestRunner.java @@ -8,10 +8,21 @@ import androidx.annotation.Nullable; import androidx.test.runner.AndroidJUnitRunner; import dev.flutter.scenariosui.ScreenshotUtil; +import io.flutter.FlutterInjector; public class TestRunner extends AndroidJUnitRunner { @Override public void onCreate(@Nullable Bundle arguments) { + String[] engineArguments = null; + if ("true".equals(arguments.getString("enable-impeller"))) { + // Set up the global settings object so that Impeller is enabled for all tests. + engineArguments = new String[] {"--enable-impeller=true"}; + } + // For consistency, just always initilaize FlutterJNI etc. + FlutterInjector.instance().flutterLoader().startInitialization(getTargetContext()); + FlutterInjector.instance() + .flutterLoader() + .ensureInitializationComplete(getTargetContext(), engineArguments); ScreenshotUtil.onCreate(); super.onCreate(arguments); } diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenarios/EngineLaunchE2ETest.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenarios/EngineLaunchE2ETest.java deleted file mode 100644 index ab874f45fb741..0000000000000 --- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenarios/EngineLaunchE2ETest.java +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2013 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. - -package dev.flutter.scenarios; - -import static org.junit.Assert.fail; - -import android.content.Context; -import androidx.test.InstrumentationRegistry; -import androidx.test.internal.runner.junit4.statement.UiThreadStatement; -import androidx.test.runner.AndroidJUnit4; -import com.google.common.util.concurrent.SettableFuture; -import io.flutter.embedding.engine.FlutterEngine; -import io.flutter.embedding.engine.dart.DartExecutor; -import java.util.Arrays; -import java.util.Locale; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class EngineLaunchE2ETest { - @Test - public void smokeTestEngineLaunch() throws Throwable { - Context applicationContext = InstrumentationRegistry.getTargetContext(); - // Specifically, create the engine without running FlutterMain first. - final AtomicReference engine = new AtomicReference<>(); - - // Run the production under test on the UI thread instead of annotating the whole test - // as @UiThreadTest because having the message handler and the CompletableFuture both being - // on the same thread will create deadlocks. - UiThreadStatement.runOnUiThread( - () -> - engine.set( - new FlutterEngine( - applicationContext, - /*dartVmArgs */ null, - /* automaticallyRegisterPlugins */ false))); - SettableFuture statusReceived = SettableFuture.create(); - - // Resolve locale to `en_US`. - // This is required, so `window.locale` in populated in dart. - // TODO: Fix race condition between sending this over the channel and starting the entrypoint. - // https://github.com/flutter/flutter/issues/55999 - UiThreadStatement.runOnUiThread( - () -> engine.get().getLocalizationChannel().sendLocales(Arrays.asList(Locale.US))); - - // The default Dart main entrypoint sends back a platform message on the "waiting_for_status" - // channel. That will be our launch success assertion condition. - engine - .get() - .getDartExecutor() - .setMessageHandler( - "waiting_for_status", (byteBuffer, binaryReply) -> statusReceived.set(Boolean.TRUE)); - - // Launching the entrypoint will run the Dart code that sends the "waiting_for_status" platform - // message. - UiThreadStatement.runOnUiThread( - () -> - engine - .get() - .getDartExecutor() - .executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault())); - - try { - Boolean result = statusReceived.get(10, TimeUnit.SECONDS); - if (!result) { - fail("expected message on waiting_for_status not received"); - } - } catch (ExecutionException e) { - fail(e.getMessage()); - } catch (InterruptedException e) { - fail(e.getMessage()); - } catch (TimeoutException e) { - fail("timed out waiting for engine started signal"); - } - // If it gets to here, statusReceived is true. - } -} diff --git a/testing/scenario_app/bin/run_android_tests.dart b/testing/scenario_app/bin/run_android_tests.dart index 6a6ed8e9bb659..85ed9a6bff544 100644 --- a/testing/scenario_app/bin/run_android_tests.dart +++ b/testing/scenario_app/bin/run_android_tests.dart @@ -190,6 +190,7 @@ Future _run({ late Process logcatProcess; late Future logcatProcessExitCode; + bool seenImpeller = false; final IOSink logcat = File(logcatPath).openWrite(); try { @@ -212,6 +213,9 @@ Future _run({ logcatOutput.listen((String line) { // Always write to the full log. logcat.writeln(line); + if (enableImpeller && !seenImpeller) { + seenImpeller = line.contains('Using the Impeller rendering backend'); + } // Conditionally parse and write to stderr. final AdbLogLine? adbLogLine = AdbLogLine.tryParse(line); @@ -316,11 +320,13 @@ Future _run({ 'am', 'instrument', '-w', - if (smokeTestFullPath != null) '-e class $smokeTestFullPath', - 'dev.flutter.scenarios.test/dev.flutter.TestRunner', - if (enableImpeller) '-e enable-impeller', + if (smokeTestFullPath != null) + '-e class $smokeTestFullPath', + if (enableImpeller) + '-e enable-impeller true', if (impellerBackend != null) '-e impeller-backend ${impellerBackend.name}', + 'dev.flutter.scenarios.test/dev.flutter.TestRunner', ]); if (exitCode != 0) { panic(['instrumented tests failed to run']); @@ -348,6 +354,16 @@ Future _run({ log('wrote logcat to $logcatPath'); }); + if (enableImpeller) { + await step('Validating Impeller...', () async { + if (!seenImpeller) { + panic([ + '--enable-impeller was specified, but Impeller was not used.', + ]); + } + }); + } + await step('Symbolize stack traces', () async { final ProcessResult result = await pm.run( [ diff --git a/testing/scenario_app/lib/main.dart b/testing/scenario_app/lib/main.dart index 6116bb1a80d82..5e76f1d7306bf 100644 --- a/testing/scenario_app/lib/main.dart +++ b/testing/scenario_app/lib/main.dart @@ -25,19 +25,14 @@ void main() { channelBuffers.setListener('driver', _handleDriverMessage); channelBuffers.setListener('write_timeline', _handleWriteTimelineMessage); - // TODO(matanlurey): https://github.com/flutter/flutter/issues/142746. - // This Dart program is used for every test, but there is at least one test - // (EngineLaunchE2ETest.java) that does not create a FlutterView, so the - // implicit view's size is not initialized (and the assert would be tripped). - // - // final FlutterView view = PlatformDispatcher.instance.implicitView!; + final FlutterView view = PlatformDispatcher.instance.implicitView!; // Asserting that this is greater than zero since this app runs on different // platforms with different sizes. If it is greater than zero, it has been // initialized to some meaningful value at least. - // assert( - // view.display.size > Offset.zero, - // 'Expected ${view.display} to be initialized.', - // ); + assert( + view.display.size > Offset.zero, + 'Expected ${view.display} to be initialized.', + ); final ByteData data = ByteData(1); data.setUint8(0, 1);