Skip to content

Add a platform view test to android_hardware_smoke_test#188069

Merged
auto-submit[bot] merged 4 commits into
flutter:masterfrom
andywolff:apktest3-revertfix
Jun 17, 2026
Merged

Add a platform view test to android_hardware_smoke_test#188069
auto-submit[bot] merged 4 commits into
flutter:masterfrom
andywolff:apktest3-revertfix

Conversation

@andywolff

@andywolff andywolff commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Expand test coverage to address more of #182123

This adds a test with a platform view. In order to get both the flutter pixels and the native pixels fully composited, we have to initiate the screenshot from the test runner, not the app. This has a few consequences for the architecture and data flow of the tests. Details in the changes to README.md.

PR #187913 (for issue #182123) added image: any to android_hardware_smoke_test's pubspec.yaml, but didn't update the pubspec.lock file in the workspace root. This lockfile doesn't currently contain the image package, so it broke CI and was reverted in #188051

A package missing from the lockfile seems to cause CI fail in this misleading way. To fix it, we just need to add image to the lockfile.

Pre-launch Checklist

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Expand test coverage to address more of
flutter#182123

This adds a test with a platform view. In order to get both the flutter
pixels and the native pixels fully composited, we have to initiate the
screenshot from the test runner, not the app. This has a few
consequences for the architecture and data flow of the tests. Details in
the changes to README.md.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [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
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[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
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 16, 2026
@github-actions github-actions Bot added the a: text input Entering text in a text field or keyboard related problems label Jun 16, 2026
@andywolff andywolff changed the title Fix revert for PR #187913 Add a platform view test to android_hardware_smoke_test Jun 16, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 16, 2026
@andywolff andywolff added the CICD Run CI/CD label Jun 16, 2026
@andywolff andywolff marked this pull request as ready for review June 16, 2026 20:27
@andywolff andywolff requested a review from gaaclarke June 16, 2026 20:27

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a platform view smoke test (platformViewTest) to the Android hardware smoke test suite, implementing a system-level screenshot strategy to capture and crop both Flutter and native Android views. Key changes include adding AndroidPlatformView and its Kotlin implementation, introducing PixelExactLocalFileComparator to compare raw pixels on-device, and updating the host-driven test runner to capture screenshots via ADB. Feedback suggests wrapping bitmap operations in a try-finally block to prevent native memory leaks, using View.of(context) for the device pixel ratio, specifying offset and length when converting ByteData to Uint8List, and removing a redundant Uint8List.fromList conversion.

Comment on lines +157 to +169
// Crop the full-screen screenshot to the exact widget bounds.
val cropped = Bitmap.createBitmap(screenshot, x, y, width, height)
if (cropped != screenshot) {
screenshot.recycle()
}

val stream = ByteArrayOutputStream()
try {
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream)
} finally {
cropped.recycle()
}
val croppedBytes = stream.toByteArray()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If Bitmap.createBitmap throws an exception (for example, due to memory pressure or unexpected state), the original screenshot bitmap will not be recycled, leading to a potential native memory leak of a large full-screen screenshot. Wrapping the creation and compression in a try-finally block ensures that both bitmaps are safely recycled under all success and failure conditions.

Suggested change
// Crop the full-screen screenshot to the exact widget bounds.
val cropped = Bitmap.createBitmap(screenshot, x, y, width, height)
if (cropped != screenshot) {
screenshot.recycle()
}
val stream = ByteArrayOutputStream()
try {
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream)
} finally {
cropped.recycle()
}
val croppedBytes = stream.toByteArray()
var cropped: Bitmap? = null
val croppedBytes = try {
cropped = Bitmap.createBitmap(screenshot, x, y, width, height)
val stream = ByteArrayOutputStream()
cropped.compress(Bitmap.CompressFormat.PNG, 100, stream)
stream.toByteArray()
} finally {
if (cropped != null && cropped != screenshot) {
screenshot.recycle()
cropped.recycle()
} else {
screenshot.recycle()
}
}

final Offset position = renderObject.localToGlobal(Offset.zero);
final Size size = renderObject.size;
// We can assume one window for these tests since they are android-only.
final double devicePixelRatio = ui.PlatformDispatcher.instance.views.first.devicePixelRatio;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of accessing the global ui.PlatformDispatcher.instance.views.first directly, it is safer and more idiomatic to use View.of(context) to retrieve the devicePixelRatio associated with the current context's view.

Suggested change
final double devicePixelRatio = ui.PlatformDispatcher.instance.views.first.devicePixelRatio;
final double devicePixelRatio = View.of(context).devicePixelRatio;

Comment on lines +46 to +47
final Uint8List list1 = bytes1.buffer.asUint8List();
final Uint8List list2 = bytes2.buffer.asUint8List();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using bytes.buffer.asUint8List() without specifying the offset and length can lead to incorrect behavior if the ByteData is a view of a larger buffer (i.e., has a non-zero offsetInBytes). It is safer and more robust to pass offsetInBytes and lengthInBytes to asUint8List.

Suggested change
final Uint8List list1 = bytes1.buffer.asUint8List();
final Uint8List list2 = bytes2.buffer.asUint8List();
final Uint8List list1 = bytes1.buffer.asUint8List(bytes1.offsetInBytes, bytes1.lengthInBytes);
final Uint8List list2 = bytes2.buffer.asUint8List(bytes2.offsetInBytes, bytes2.lengthInBytes);

);
}
final img.Image cropped = img.copyCrop(decoded, x: x, y: y, width: w, height: h);
imageBytes = Uint8List.fromList(img.encodePng(cropped));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In the image package version 4.x, img.encodePng already returns a Uint8List. Wrapping it in Uint8List.fromList is redundant and performs an unnecessary memory allocation and copy of the entire image byte array.

Suggested change
imageBytes = Uint8List.fromList(img.encodePng(cropped));
imageBytes = img.encodePng(cropped);

@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 16, 2026

@gaaclarke gaaclarke left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! godspeed little pr

@andywolff andywolff added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 16, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 16, 2026
@auto-submit

auto-submit Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

auto label is removed for flutter/flutter/188069, Failed to enqueue flutter/flutter/188069 with HTTP 400: Pull request Required status check "Merge Queue Guard" is expected..

@andywolff andywolff added autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD labels Jun 17, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue Jun 17, 2026
Merged via the queue into flutter:master with commit 08109a7 Jun 17, 2026
30 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 17, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Jun 17, 2026
flutter/flutter@3a0420c...b10d0f1

2026-06-17 mr-peipei@web.de Skip platform-specific plugin registration if no platforms enabled (flutter/flutter#186304)
2026-06-17 engine-flutter-autoroll@skia.org Roll Packages from 8286d39 to 6ce00a8 (1 revision) (flutter/flutter#188109)
2026-06-17 engine-flutter-autoroll@skia.org Roll Skia from 79f93fd5f36e to 5d19002eb73e (1 revision) (flutter/flutter#188108)
2026-06-17 simon@journeyapps.com Import `dart:_js_interop_wasm` in addition to `dart:_wasm` to convert between `JSAny` and `WasmExternRef?` (flutter/flutter#186974)
2026-06-17 engine-flutter-autoroll@skia.org Roll Dart SDK from f811ecae9ca0 to e39bde5b1bfc (2 revisions) (flutter/flutter#188107)
2026-06-17 engine-flutter-autoroll@skia.org Roll Skia from 026f6a6be2b9 to 79f93fd5f36e (1 revision) (flutter/flutter#188105)
2026-06-17 engine-flutter-autoroll@skia.org Roll Dart SDK from 462bf0a1d489 to f811ecae9ca0 (1 revision) (flutter/flutter#188099)
2026-06-17 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from VeLhhlDcod09NR4Hb... to or21OEdGtairm6nl9... (flutter/flutter#188098)
2026-06-17 engine-flutter-autoroll@skia.org Roll Skia from 2ffd155313f5 to 026f6a6be2b9 (10 revisions) (flutter/flutter#188097)
2026-06-17 engine-flutter-autoroll@skia.org Roll Dart SDK from 824b4b48b6d4 to 462bf0a1d489 (1 revision) (flutter/flutter#188093)
2026-06-17 jason-simmons@users.noreply.github.com Manual Dart roll from f6c31f4c3a63 to 824b4b48b6d4 (flutter/flutter#188023)
2026-06-17 awolff@google.com Add a platform view test to android_hardware_smoke_test (flutter/flutter#188069)
2026-06-17 44747303+theprantadutta@users.noreply.github.com [flutter_tools] Format empty app template with latest dart format (flutter/flutter#187443)
2026-06-16 49699333+dependabot[bot]@users.noreply.github.com Bump the all-github-actions group across 1 directory with 3 updates (flutter/flutter#188086)
2026-06-16 engine-flutter-autoroll@skia.org Roll Skia from d7196b0b4939 to 2ffd155313f5 (9 revisions) (flutter/flutter#188081)
2026-06-16 43089218+chika3742@users.noreply.github.com Prevent downgrading `project.pbxproj` when greater version number (flutter/flutter#186250)
2026-06-16 magder@google.com Only allow dependabot to autoupdate GitHub-owned actions (flutter/flutter#187936)
2026-06-16 matt.boetger@gmail.com Fall back to source AndroidManifest.xml if AAPT fails or returns garbage (flutter/flutter#187197)
2026-06-16 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#187769)
2026-06-16 jason-simmons@users.noreply.github.com [Impeller] Move queue submission into a callback that is invoked by FenceWaiterVK::AddFence only if it can accept the fence (flutter/flutter#187761)
2026-06-16 jhy03261997@gmail.com Reland [a11y] Map some framework semantics roles to android classes.  (flutter/flutter#188037)
2026-06-16 1961493+harryterkelsen@users.noreply.github.com refactor(web): Unify Image on Skwasm and CanvasKit (flutter/flutter#187873)
2026-06-16 30870216+gaaclarke@users.noreply.github.com Adds arm64 variant of impeller devicelab tests for windows. (flutter/flutter#188053)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC bmparr@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@andywolff andywolff deleted the apktest3-revertfix branch June 17, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems CICD Run CI/CD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants