Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b8752bb

Browse files
christopherfujinoEmmanuel Garciagaaclarkejason-simmons
authored
[flutter_releases] Flutter 1.22.2 engine cherrypicks (#21841)
* Update engine to use Dart 2.10.2 * Ensure JNI is not called from raster thread (#21665) * Revert "fix On iOS, dialog titles are announced twice (#19826)" (#21714) * Call PlatformView.dispose when removing hybrid composition platform views (#21790) Also force disposal of all hybrid platform views when shutting down the engine. Fixes flutter/flutter#66764 * Add XCTest.h to build rules Co-authored-by: Emmanuel Garcia <egarciad@google.com> Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Co-authored-by: Jason Simmons <jason-simmons@users.noreply.github.com>
1 parent 7386112 commit b8752bb

File tree

13 files changed

+216
-81
lines changed

13 files changed

+216
-81
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ vars = {
3434
# Dart is: https://github.com/dart-lang/sdk/blob/master/DEPS.
3535
# You can use //tools/dart/create_updated_flutter_deps.py to produce
3636
# updated revision list of existing dependencies.
37-
'dart_revision': 'efd753621946a89008b76b76d85d54d1aa57fce8',
37+
'dart_revision': '1d923a386d7a9f384435a2b4c1287b2937504566',
3838

3939
# WARNING: DO NOT EDIT MANUALLY
4040
# The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py

shell/platform/android/external_view_embedder/external_view_embedder.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,15 +265,17 @@ void AndroidExternalViewEmbedder::BeginFrame(
265265

266266
// The surface size changed. Therefore, destroy existing surfaces as
267267
// the existing surfaces in the pool can't be recycled.
268-
if (frame_size_ != frame_size) {
268+
if (frame_size_ != frame_size && raster_thread_merger->IsOnPlatformThread()) {
269269
surface_pool_->DestroyLayers(jni_facade_);
270270
}
271-
frame_size_ = frame_size;
272-
device_pixel_ratio_ = device_pixel_ratio;
271+
surface_pool_->SetFrameSize(frame_size);
273272
// JNI method must be called on the platform thread.
274273
if (raster_thread_merger->IsOnPlatformThread()) {
275274
jni_facade_->FlutterViewBeginFrame();
276275
}
276+
277+
frame_size_ = frame_size;
278+
device_pixel_ratio_ = device_pixel_ratio;
277279
}
278280

279281
// |ExternalViewEmbedder|

shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,91 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
556556
raster_thread_merger);
557557
}
558558

559+
TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) {
560+
auto jni_mock = std::make_shared<JNIMock>();
561+
auto android_context =
562+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
563+
564+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
565+
auto gr_context = GrDirectContext::MakeMock(nullptr);
566+
auto frame_size = SkISize::Make(1000, 1000);
567+
auto surface_factory =
568+
[gr_context, window, frame_size](
569+
std::shared_ptr<AndroidContext> android_context,
570+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
571+
auto surface_frame_1 = std::make_unique<SurfaceFrame>(
572+
SkSurface::MakeNull(1000, 1000), false,
573+
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
574+
return true;
575+
});
576+
577+
auto surface_mock = std::make_unique<SurfaceMock>();
578+
EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
579+
.WillOnce(Return(ByMove(std::move(surface_frame_1))));
580+
581+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
582+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
583+
584+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
585+
.WillOnce(Return(ByMove(std::move(surface_mock))));
586+
587+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
588+
589+
return android_surface_mock;
590+
};
591+
592+
auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
593+
android_context, jni_mock, surface_factory);
594+
595+
// ------------------ First frame ------------------ //
596+
{
597+
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
598+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
599+
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
600+
601+
// Add an Android view.
602+
MutatorsStack stack1;
603+
// TODO(egarciad): Investigate why Flow applies the device pixel ratio to
604+
// the offsetPixels, but not the sizePoints.
605+
auto view_params_1 = std::make_unique<EmbeddedViewParams>(
606+
SkMatrix(), SkSize::Make(200, 200), stack1);
607+
608+
embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
609+
610+
// This simulates Flutter UI that intersects with the Android view.
611+
embedder->CompositeEmbeddedView(0)->drawRect(
612+
SkRect::MakeXYWH(50, 50, 200, 200), SkPaint());
613+
614+
// Create a new overlay surface.
615+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
616+
.WillOnce(Return(
617+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
618+
0, window))));
619+
// The JNI call to display the Android view.
620+
EXPECT_CALL(*jni_mock, FlutterViewOnDisplayPlatformView(0, 0, 0, 200, 200,
621+
300, 300, stack1));
622+
EXPECT_CALL(*jni_mock,
623+
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
624+
625+
auto surface_frame =
626+
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
627+
[](const SurfaceFrame& surface_frame,
628+
SkCanvas* canvas) { return true; });
629+
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
630+
631+
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
632+
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
633+
}
634+
635+
// Changing the frame size from the raster thread does not make JNI calls.
636+
637+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
638+
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
639+
640+
embedder->BeginFrame(SkISize::Make(30, 40), nullptr, 1.0,
641+
GetThreadMergerFromRasterThread());
642+
}
643+
559644
TEST(AndroidExternalViewEmbedder, SupportsDynamicThreadMerging) {
560645
auto jni_mock = std::make_shared<JNIMock>();
561646

shell/platform/android/external_view_embedder/surface_pool.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
2424
std::shared_ptr<AndroidContext> android_context,
2525
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
2626
const AndroidSurface::Factory& surface_factory) {
27+
// Destroy current layers in the pool if the frame size has changed.
28+
if (requested_frame_size_ != current_frame_size_) {
29+
DestroyLayers(jni_facade);
30+
}
31+
2732
intptr_t gr_context_key = reinterpret_cast<intptr_t>(gr_context);
2833
// Allocate a new surface if there isn't one available.
2934
if (available_layer_index_ >= layers_.size()) {
@@ -63,6 +68,7 @@ std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
6368
layer->surface = std::move(surface);
6469
}
6570
available_layer_index_++;
71+
current_frame_size_ = requested_frame_size_;
6672
return layer;
6773
}
6874

@@ -87,4 +93,8 @@ std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {
8793
return results;
8894
}
8995

96+
void SurfacePool::SetFrameSize(SkISize frame_size) {
97+
requested_frame_size_ = frame_size;
98+
}
99+
90100
} // namespace flutter

shell/platform/android/external_view_embedder/surface_pool.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class SurfacePool {
6767
// Destroys all the layers in the pool.
6868
void DestroyLayers(std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
6969

70+
// Sets the frame size used by the layers in the pool.
71+
// If the current layers in the pool have a different frame size,
72+
// then they are deallocated as soon as |GetLayer| is called.
73+
void SetFrameSize(SkISize frame_size);
74+
7075
private:
7176
// The index of the entry in the layers_ vector that determines the beginning
7277
// of the unused layers. For example, consider the following vector:
@@ -81,7 +86,15 @@ class SurfacePool {
8186
// This indicates that entries starting from 1 can be reused meanwhile the
8287
// entry at position 0 cannot be reused.
8388
size_t available_layer_index_ = 0;
89+
90+
// The layers in the pool.
8491
std::vector<std::shared_ptr<OverlayLayer>> layers_;
92+
93+
// The frame size of the layers in the pool.
94+
SkISize current_frame_size_;
95+
96+
// The frame size to be used by future layers.
97+
SkISize requested_frame_size_;
8598
};
8699

87100
} // namespace flutter

shell/platform/android/external_view_embedder/surface_pool_unittests.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,46 @@ TEST(SurfacePool, DestroyLayers) {
201201
ASSERT_TRUE(pool->GetUnusedLayers().empty());
202202
}
203203

204+
TEST(SurfacePool, DestroyLayers__frameSizeChanged) {
205+
auto pool = std::make_unique<SurfacePool>();
206+
auto jni_mock = std::make_shared<JNIMock>();
207+
208+
auto gr_context = GrDirectContext::MakeMock(nullptr);
209+
auto android_context =
210+
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
211+
212+
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
213+
214+
auto surface_factory =
215+
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
216+
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
217+
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
218+
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
219+
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
220+
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
221+
return android_surface_mock;
222+
};
223+
pool->SetFrameSize(SkISize::Make(10, 10));
224+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
225+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
226+
.Times(1)
227+
.WillOnce(Return(
228+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
229+
0, window))));
230+
231+
pool->GetLayer(gr_context.get(), android_context, jni_mock, surface_factory);
232+
233+
pool->SetFrameSize(SkISize::Make(20, 20));
234+
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(1);
235+
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
236+
.Times(1)
237+
.WillOnce(Return(
238+
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
239+
1, window))));
240+
pool->GetLayer(gr_context.get(), android_context, jni_mock, surface_factory);
241+
242+
ASSERT_TRUE(pool->GetUnusedLayers().empty());
243+
}
244+
204245
} // namespace testing
205246
} // namespace flutter

shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import android.util.SparseArray;
1616
import android.view.MotionEvent;
1717
import android.view.View;
18+
import android.view.ViewGroup;
1819
import android.widget.FrameLayout;
1920
import androidx.annotation.NonNull;
2021
import androidx.annotation.Nullable;
@@ -83,7 +84,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
8384
// The views returned by `PlatformView#getView()`.
8485
//
8586
// This only applies to hybrid composition.
86-
private final SparseArray<View> platformViews;
87+
private final SparseArray<PlatformView> platformViews;
8788

8889
// The platform view parents that are appended to `FlutterView`.
8990
// If an entry in `platformViews` doesn't have an entry in this array, the platform view isn't
@@ -143,32 +144,24 @@ public void createAndroidViewForPlatformView(
143144
}
144145

145146
final PlatformView platformView = factory.create(context, request.viewId, createParams);
146-
final View view = platformView.getView();
147-
if (view == null) {
148-
throw new IllegalStateException(
149-
"PlatformView#getView() returned null, but an Android view reference was expected.");
150-
}
151-
if (view.getParent() != null) {
152-
throw new IllegalStateException(
153-
"The Android view returned from PlatformView#getView() was already added to a parent view.");
154-
}
155-
platformViews.put(request.viewId, view);
147+
platformViews.put(request.viewId, platformView);
156148
}
157149

158150
@Override
159151
public void disposeAndroidViewForPlatformView(int viewId) {
160152
// Hybrid view.
161-
final View platformView = platformViews.get(viewId);
153+
final PlatformView platformView = platformViews.get(viewId);
162154
final FlutterMutatorView parentView = platformViewParent.get(viewId);
163155
if (platformView != null) {
164156
if (parentView != null) {
165-
parentView.removeView(platformView);
157+
parentView.removeView(platformView.getView());
166158
}
167159
platformViews.remove(viewId);
160+
platformView.dispose();
168161
}
169162

170163
if (parentView != null) {
171-
((FlutterView) flutterView).removeView(parentView);
164+
((ViewGroup) parentView.getParent()).removeView(parentView);
172165
platformViewParent.remove(viewId);
173166
}
174167
}
@@ -311,8 +304,10 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
311304
vdControllers.get(touch.viewId).dispatchTouchEvent(event);
312305
} else if (platformViews.get(viewId) != null) {
313306
final MotionEvent event = toMotionEvent(density, touch, /*usingVirtualDiplays=*/ false);
314-
View view = platformViews.get(touch.viewId);
315-
view.dispatchTouchEvent(event);
307+
View view = platformViews.get(touch.viewId).getView();
308+
if (view != null) {
309+
view.dispatchTouchEvent(event);
310+
}
316311
} else {
317312
throw new IllegalStateException("Sending touch to an unknown view with id: " + viewId);
318313
}
@@ -578,7 +573,7 @@ public void onPreEngineRestart() {
578573
public View getPlatformViewById(Integer id) {
579574
// Hybrid composition.
580575
if (platformViews.get(id) != null) {
581-
return platformViews.get(id);
576+
return platformViews.get(id).getView();
582577
}
583578
VirtualDisplayController controller = vdControllers.get(id);
584579
if (controller == null) {
@@ -688,6 +683,10 @@ private void flushAllViews() {
688683
controller.dispose();
689684
}
690685
vdControllers.clear();
686+
687+
while (platformViews.size() > 0) {
688+
channelHandler.disposeAndroidViewForPlatformView(platformViews.keyAt(0));
689+
}
691690
}
692691

693692
private void initializeRootImageViewIfNeeded() {
@@ -699,19 +698,27 @@ private void initializeRootImageViewIfNeeded() {
699698

700699
@VisibleForTesting
701700
void initializePlatformViewIfNeeded(int viewId) {
702-
final View view = platformViews.get(viewId);
703-
if (view == null) {
701+
final PlatformView platformView = platformViews.get(viewId);
702+
if (platformView == null) {
704703
throw new IllegalStateException(
705704
"Platform view hasn't been initialized from the platform view channel.");
706705
}
707706
if (platformViewParent.get(viewId) != null) {
708707
return;
709708
}
709+
if (platformView.getView() == null) {
710+
throw new IllegalStateException(
711+
"PlatformView#getView() returned null, but an Android view reference was expected.");
712+
}
713+
if (platformView.getView().getParent() != null) {
714+
throw new IllegalStateException(
715+
"The Android view returned from PlatformView#getView() was already added to a parent view.");
716+
}
710717
final FlutterMutatorView parentView =
711718
new FlutterMutatorView(
712719
context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);
713720
platformViewParent.put(viewId, parentView);
714-
parentView.addView(view);
721+
parentView.addView(platformView.getView());
715722
((FlutterView) flutterView).addView(parentView);
716723
}
717724

@@ -738,9 +745,11 @@ public void onDisplayPlatformView(
738745

739746
final FrameLayout.LayoutParams layoutParams =
740747
new FrameLayout.LayoutParams(viewWidth, viewHeight);
741-
final View platformView = platformViews.get(viewId);
742-
platformView.setLayoutParams(layoutParams);
743-
platformView.bringToFront();
748+
final View view = platformViews.get(viewId).getView();
749+
if (view != null) {
750+
view.setLayoutParams(layoutParams);
751+
view.bringToFront();
752+
}
744753
currentFrameUsedPlatformViewIds.add(viewId);
745754
}
746755

0 commit comments

Comments
 (0)