diff --git a/ci/builders/linux_android_emulator.json b/ci/builders/linux_android_emulator.json index 643eb4da6c744..ab6da20cb0bf9 100644 --- a/ci/builders/linux_android_emulator.json +++ b/ci/builders/linux_android_emulator.json @@ -58,7 +58,7 @@ }, { "language": "bash", - "name": "Scenario App Integration Tests", + "name": "Android Scenario App Integration Tests (Skia)", "test_dependencies": [ { "dependency": "android_virtual_device", @@ -74,7 +74,54 @@ ], "script": "flutter/testing/scenario_app/run_android_tests.sh", "parameters": [ - "android_debug_x64" + "android_debug_x64", + "--no-enable-impeller" + ] + }, + { + "language": "bash", + "name": "Android Scenario App Integration Tests (Impeller/Vulkan)", + "test_dependencies": [ + { + "dependency": "android_virtual_device", + "version": "android_34_google_apis_x64.textpb" + }, + { + "dependency": "avd_cipd_version", + "version": "build_id:8759428741582061553" + } + ], + "contexts": [ + "android_virtual_device" + ], + "script": "flutter/testing/scenario_app/run_android_tests.sh", + "parameters": [ + "android_debug_x64", + "--enable-impeller", + "--impeller-backend=vulkan" + ] + }, + { + "language": "bash", + "name": "Android Scenario App Integration Tests (Impeller/OpenGLES)", + "test_dependencies": [ + { + "dependency": "android_virtual_device", + "version": "android_34_google_apis_x64.textpb" + }, + { + "dependency": "avd_cipd_version", + "version": "build_id:8759428741582061553" + } + ], + "contexts": [ + "android_virtual_device" + ], + "script": "flutter/testing/scenario_app/run_android_tests.sh", + "parameters": [ + "android_debug_x64", + "--enable-impeller", + "--impeller-backend=opengles" ] } ] diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java index 79d3615f78856..013b97244b03e 100644 --- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java +++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/TestActivity.java @@ -32,12 +32,13 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; public abstract class TestActivity extends TestableFlutterActivity { static final String TAG = "Scenarios"; - private Runnable resultsTask = + private final Runnable resultsTask = new Runnable() { @Override public void run() { @@ -47,7 +48,7 @@ public void run() { } }; - private Handler handler = new Handler(); + private final Handler handler = new Handler(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -85,7 +86,10 @@ public FlutterShellArgs getFlutterShellArgs() { public void onFlutterUiDisplayed() { final Intent launchIntent = getIntent(); MethodChannel channel = - new MethodChannel(getFlutterEngine().getDartExecutor(), "driver", JSONMethodCodec.INSTANCE); + new MethodChannel( + Objects.requireNonNull(getFlutterEngine()).getDartExecutor(), + "driver", + JSONMethodCodec.INSTANCE); Map test = new HashMap<>(2); if (launchIntent.hasExtra("scenario_name")) { test.put("name", launchIntent.getStringExtra("scenario_name")); @@ -125,8 +129,10 @@ protected void writeTimelineData(@Nullable Uri logFile) { AssetFileDescriptor afd = null; try { afd = getContentResolver().openAssetFileDescriptor(logFile, "w"); + assert afd != null; final FileDescriptor fd = afd.getFileDescriptor(); final FileOutputStream outputStream = new FileOutputStream(fd); + assert reply != null; outputStream.write(reply.array()); outputStream.close(); } catch (IOException ex) { @@ -190,6 +196,7 @@ public void run() { private static void hideSystemBars(Window window) { final WindowInsetsControllerCompat insetController = WindowCompat.getInsetsController(window, window.getDecorView()); + assert insetController != null; insetController.setSystemBarsBehavior( WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); insetController.hide(WindowInsetsCompat.Type.systemBars()); diff --git a/testing/scenario_app/bin/android_integration_tests.dart b/testing/scenario_app/bin/android_integration_tests.dart index 07b31d0a4a97d..3332de5f7f81d 100644 --- a/testing/scenario_app/bin/android_integration_tests.dart +++ b/testing/scenario_app/bin/android_integration_tests.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -32,12 +33,21 @@ void main(List args) async { ..addOption( 'smoke-test', help: 'runs a single test to verify the setup', - valueHelp: 'The class to execute, defaults to dev.flutter.scenarios.EngineLaunchE2ETest', ) ..addFlag( 'use-skia-gold', help: 'Use Skia Gold to compare screenshots.', defaultsTo: isLuciEnv, + ) + ..addFlag( + 'enable-impeller', + help: 'Enable Impeller for the Android app.', + ) + ..addOption( + 'impeller-backend', + help: 'The Impeller backend to use for the Android app.', + allowed: ['vulkan', 'opengles'], + defaultsTo: 'vulkan', ); runZonedGuarded( @@ -46,15 +56,19 @@ void main(List args) async { final Directory outDir = Directory(results['out-dir'] as String); final File adb = File(results['adb'] as String); final bool useSkiaGold = results['use-skia-gold'] as bool; - String? smokeTest = results['smoke-test'] as String?; - if (results.wasParsed('smoke-test') && smokeTest!.isEmpty) { - smokeTest = 'dev.flutter.scenarios.EngineLaunchE2ETest'; + final String? smokeTest = results['smoke-test'] as String?; + final bool enableImpeller = results['enable-impeller'] as bool; + final _ImpellerBackend? impellerBackend = _ImpellerBackend.tryParse(results['impeller-backend'] as String?); + if (enableImpeller && impellerBackend == null) { + panic(['invalid graphics-backend', results['impeller-backend'] as String? ?? '']); } await _run( outDir: outDir, adb: adb, smokeTestFullPath: smokeTest, useSkiaGold: useSkiaGold, + enableImpeller: enableImpeller, + impellerBackend: impellerBackend, ); exit(0); }, @@ -68,11 +82,27 @@ void main(List args) async { ); } +enum _ImpellerBackend { + vulkan, + opengles; + + static _ImpellerBackend? tryParse(String? value) { + for (final _ImpellerBackend backend in _ImpellerBackend.values) { + if (backend.name == value) { + return backend; + } + } + return null; + } +} + Future _run({ required Directory outDir, required File adb, required String? smokeTestFullPath, required bool useSkiaGold, + required bool enableImpeller, + required _ImpellerBackend? impellerBackend, }) async { const ProcessManager pm = LocalProcessManager(); @@ -179,11 +209,16 @@ Future _run({ panic(['could not get API level of the connected device']); } final String connectedDeviceAPILevel = (apiLevelProcessResult.stdout as String).trim(); - log('using API level $connectedDeviceAPILevel'); + final Map dimensions = { + 'AndroidAPILevel': connectedDeviceAPILevel, + 'GraphicsBackend': enableImpeller ? 'impeller-${impellerBackend!.name}' : 'skia', + }; + log('using dimensions: ${json.encode(dimensions)}'); skiaGoldClient = SkiaGoldClient( outDir, dimensions: { 'AndroidAPILevel': connectedDeviceAPILevel, + 'GraphicsBackend': enableImpeller ? 'impeller-${impellerBackend!.name}' : 'skia', }, ); }); @@ -232,6 +267,10 @@ Future _run({ if (smokeTestFullPath != null) '-e class $smokeTestFullPath', 'dev.flutter.scenarios.test/dev.flutter.TestRunner', + if (enableImpeller) + '-e enable-impeller', + if (impellerBackend != null) + '-e impeller-backend ${impellerBackend.name}', ]); if (exitCode != 0) { panic(['instrumented tests failed to run']); diff --git a/testing/scenario_app/bin/utils/logs.dart b/testing/scenario_app/bin/utils/logs.dart index 3132164300dde..af5f68c75fc8e 100644 --- a/testing/scenario_app/bin/utils/logs.dart +++ b/testing/scenario_app/bin/utils/logs.dart @@ -25,7 +25,7 @@ void log(String msg) { final class Panic extends Error {} -void panic(List messages) { +Never panic(List messages) { for (final String message in messages) { stderr.writeln('$_red$message$_reset'); } diff --git a/testing/scenario_app/run_android_tests.sh b/testing/scenario_app/run_android_tests.sh index ec4abf49cb1c8..5a61d7d7ef584 100755 --- a/testing/scenario_app/run_android_tests.sh +++ b/testing/scenario_app/run_android_tests.sh @@ -68,4 +68,5 @@ cd $SCRIPT_DIR "$SRC_DIR"/third_party/dart/tools/sdks/dart-sdk/bin/dart run \ "$SCRIPT_DIR"/bin/android_integration_tests.dart \ --adb="$SRC_DIR"/third_party/android_tools/sdk/platform-tools/adb \ - --out-dir="$OUT_DIR" + --out-dir="$OUT_DIR" \ + "$@" diff --git a/testing/scenario_app/tool/run_android_tests_smoke.sh b/testing/scenario_app/tool/run_android_tests_smoke.sh index f04da36fc6594..4a3f2d03657b6 100755 --- a/testing/scenario_app/tool/run_android_tests_smoke.sh +++ b/testing/scenario_app/tool/run_android_tests_smoke.sh @@ -12,7 +12,7 @@ ../third_party/dart/tools/sdks/dart-sdk/bin/dart ./testing/scenario_app/bin/android_integration_tests.dart \ --adb="../third_party/android_tools/sdk/platform-tools/adb" \ --out-dir="../out/android_debug_unopt_arm64" \ - --smoke-test + --smoke-test="dev.flutter.scenarios.EngineLaunchE2ETest" echo "Exit code: $?" echo "Done"