Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ void Rasterizer::Teardown() {
surface_.reset();
last_layer_tree_.reset();

if (raster_thread_merger_.get() != nullptr &&
raster_thread_merger_.get()->IsMerged()) {
if (raster_thread_merger_ && raster_thread_merger_->IsMerged()) {
FML_DCHECK(raster_thread_merger_->IsEnabled());
raster_thread_merger_->UnMergeNowIfLastOne();
raster_thread_merger_->SetMergeUnmergeCallback(nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrDirectContext* context,
// |ExternalViewEmbedder|
PostPrerollResult AndroidExternalViewEmbedder::PostPrerollAction(
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
if (!FrameHasPlatformLayers()) {
if (!FrameHasPlatformLayers() || !raster_thread_merger) {
return PostPrerollResult::kSuccess;
}
if (!raster_thread_merger->IsMerged()) {
Expand Down Expand Up @@ -264,14 +264,12 @@ void AndroidExternalViewEmbedder::BeginFrame(

// The surface size changed. Therefore, destroy existing surfaces as
// the existing surfaces in the pool can't be recycled.
if (frame_size_ != frame_size && raster_thread_merger->IsOnPlatformThread()) {
if (frame_size_ != frame_size) {
surface_pool_->DestroyLayers(jni_facade_);
}
surface_pool_->SetFrameSize(frame_size);
// JNI method must be called on the platform thread.
if (raster_thread_merger->IsOnPlatformThread()) {
jni_facade_->FlutterViewBeginFrame();
}
jni_facade_->FlutterViewBeginFrame();

frame_size_ = frame_size;
device_pixel_ratio_ = device_pixel_ratio;
Expand All @@ -288,14 +286,12 @@ void AndroidExternalViewEmbedder::EndFrame(
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
surface_pool_->RecycleLayers();
// JNI method must be called on the platform thread.
if (raster_thread_merger->IsOnPlatformThread()) {
jni_facade_->FlutterViewEndFrame();
}
jni_facade_->FlutterViewEndFrame();
}

// |ExternalViewEmbedder|
bool AndroidExternalViewEmbedder::SupportsDynamicThreadMerging() {
return true;
return false;
}

} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ public boolean acquireLatestImage() {
if (!isAttachedToFlutterRenderer) {
return false;
}
if (currentImage != null) {
return true;
}
// 1. `acquireLatestImage()` may return null if no new image is available.
// 2. There's no guarantee that `onDraw()` is called after `invalidate()`.
// For example, the device may not produce new frames if it's in sleep mode
Expand Down
83 changes: 51 additions & 32 deletions shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.graphics.ImageDecoder;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Size;
import android.view.Surface;
Expand Down Expand Up @@ -1006,40 +1007,45 @@ private void onPreEngineRestart() {
@SuppressWarnings("unused")
@UiThread
public void onDisplayOverlaySurface(int id, int x, int y, int width, int height) {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to position an overlay surface");
}
platformViewsController.onDisplayOverlaySurface(id, x, y, width, height);
runOnMainThread(
() -> {
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to position an overlay surface");
}
platformViewsController.onDisplayOverlaySurface(id, x, y, width, height);
});
}

@SuppressWarnings("unused")
@UiThread
public void onBeginFrame() {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to begin the frame");
}
platformViewsController.onBeginFrame();
runOnMainThread(
() -> {
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to begin the frame");
}
platformViewsController.onBeginFrame();
});
}

@SuppressWarnings("unused")
@UiThread
public void onEndFrame() {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to end the frame");
}
platformViewsController.onEndFrame();
runOnMainThread(
() -> {
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to end the frame");
}
platformViewsController.onEndFrame();
});
}

@SuppressWarnings("unused")
@UiThread
public FlutterOverlaySurface createOverlaySurface() {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to position an overlay surface");
Expand All @@ -1050,12 +1056,14 @@ public FlutterOverlaySurface createOverlaySurface() {
@SuppressWarnings("unused")
@UiThread
public void destroyOverlaySurfaces() {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to destroy an overlay surface");
}
platformViewsController.destroyOverlaySurfaces();
runOnMainThread(
() -> {
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to destroy an overlay surface");
}
platformViewsController.destroyOverlaySurfaces();
});
}
// ----- End Engine Lifecycle Support ----

Expand Down Expand Up @@ -1241,13 +1249,15 @@ public void onDisplayPlatformView(
int viewWidth,
int viewHeight,
FlutterMutatorsStack mutatorsStack) {
ensureRunningOnMainThread();
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to position a platform view");
}
platformViewsController.onDisplayPlatformView(
viewId, x, y, width, height, viewWidth, viewHeight, mutatorsStack);
runOnMainThread(
() -> {
if (platformViewsController == null) {
throw new RuntimeException(
"platformViewsController must be set before attempting to position a platform view");
}
platformViewsController.onDisplayPlatformView(
viewId, x, y, width, height, viewWidth, viewHeight, mutatorsStack);
});
}

// TODO(mattcarroll): determine if this is nonull or nullable
Expand Down Expand Up @@ -1285,6 +1295,15 @@ private void ensureRunningOnMainThread() {
}
}

private void runOnMainThread(Runnable fn) {
if (Looper.myLooper() == mainLooper) {
fn.run();
return;
}
final Handler handler = new Handler(mainLooper);
handler.post(fn);
}

/**
* Delegate responsible for creating and updating Android-side caches of Flutter's semantics tree
* and custom accessibility actions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,16 @@ public void readyToDisplay(
this.mutatorsStack = mutatorsStack;
this.left = left;
this.top = top;
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
layoutParams.leftMargin = left;
layoutParams.topMargin = top;
setLayoutParams(layoutParams);
final FrameLayout.LayoutParams currentLayout = (FrameLayout.LayoutParams) getLayoutParams();
if (currentLayout.width != width
|| currentLayout.height != height
|| currentLayout.leftMargin != left
|| currentLayout.topMargin != top) {
final FrameLayout.LayoutParams newLayoutParams = new FrameLayout.LayoutParams(width, height);
newLayoutParams.leftMargin = left;
newLayoutParams.topMargin = top;
setLayoutParams(newLayoutParams);
}
setWillNotDraw(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,23 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
private boolean synchronizeToNativeViewHierarchy = true;

// Overlay layer IDs that were displayed since the start of the current frame.
private HashSet<Integer> currentFrameUsedOverlayLayerIds;
private final HashSet<Integer> currentFrameUsedOverlayLayerIds;

// Platform view IDs that were displayed since the start of the current frame.
private HashSet<Integer> currentFrameUsedPlatformViewIds;
private final HashSet<Integer> currentFrameUsedPlatformViewIds;

// The z-order of the views owned by controller that live in FlutterView.
// This is a stack that provides efficient querying of the views z-order.
private final SparseArray<View> viewZorder;

// The index of a view in viewZorder.
//
// This is used to determinate if the view is in the expected z-order.
// For example, if viewZorderIndex is 1, the view for index 1 in viewZorder must equal
// to the expected view in order to be considered in the correct order.
//
// This value is reset to 0 when the frame starts.
private int viewZorderIndex = 0;

// Used to acquire the original motion events using the motionEventIds.
private final MotionEventTracker motionEventTracker;
Expand Down Expand Up @@ -431,6 +444,7 @@ public PlatformViewsController() {
overlayLayerViews = new SparseArray<>();
currentFrameUsedOverlayLayerIds = new HashSet<>();
currentFrameUsedPlatformViewIds = new HashSet<>();
viewZorder = new SparseArray<>();

platformViews = new SparseArray<>();
platformViewParent = new SparseArray<>();
Expand Down Expand Up @@ -502,6 +516,9 @@ public void attachToView(@NonNull View flutterView) {
*/
public void detachFromView() {
destroyOverlaySurfaces();
destroyHybridPlatformViews();
viewZorder.clear();

this.flutterView = null;
flutterViewConvertedToImageView = false;

Expand Down Expand Up @@ -716,6 +733,10 @@ private void flushAllViews() {
if (contextToPlatformView.size() > 0) {
contextToPlatformView.clear();
}

destroyOverlaySurfaces();
destroyHybridPlatformViews();
viewZorder.clear();
}

private void initializeRootImageViewIfNeeded() {
Expand Down Expand Up @@ -798,15 +819,21 @@ public void onDisplayPlatformView(

final FlutterMutatorView parentView = platformViewParent.get(viewId);
parentView.readyToDisplay(mutatorsStack, x, y, width, height);

parentView.setVisibility(View.VISIBLE);
parentView.bringToFront();
bringViewToFrontIfNeeded(parentView);

final FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(viewWidth, viewHeight);
final View view = platformViews.get(viewId).getView();
if (view != null) {
view.setLayoutParams(layoutParams);
view.bringToFront();
final ViewGroup.LayoutParams viewLayoutParams = view.getLayoutParams();
// setLayoutParams schedules a layout even when the params haven't changed.
// This is expensive on low end devices.
if (viewLayoutParams.width != viewWidth || viewLayoutParams.height != viewHeight) {
final FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(viewWidth, viewHeight);

view.setLayoutParams(layoutParams);
}
}
currentFrameUsedPlatformViewIds.add(viewId);
}
Expand All @@ -832,20 +859,46 @@ public void onDisplayOverlaySurface(int id, int x, int y, int width, int height)
((FlutterView) flutterView).addView(overlayView);
}

FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams((int) width, (int) height);
layoutParams.leftMargin = (int) x;
layoutParams.topMargin = (int) y;
overlayView.setLayoutParams(layoutParams);
// setLayoutParams schedules a layout even when the params haven't changed.
// This is expensive on low end devices.
final FrameLayout.LayoutParams currentParams =
(FrameLayout.LayoutParams) overlayView.getLayoutParams();
if (currentParams.width != width
|| currentParams.height != height
|| currentParams.leftMargin != x
|| currentParams.topMargin != y) {
FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams((int) width, (int) height);
layoutParams.leftMargin = (int) x;
layoutParams.topMargin = (int) y;
overlayView.setLayoutParams(layoutParams);
}

overlayView.setVisibility(View.VISIBLE);
overlayView.bringToFront();
bringViewToFrontIfNeeded(overlayView);
currentFrameUsedOverlayLayerIds.add(id);
}

public void onBeginFrame() {
viewZorderIndex = 0;
currentFrameUsedOverlayLayerIds.clear();
currentFrameUsedPlatformViewIds.clear();
}

/** @param view The view that should be */
private void bringViewToFrontIfNeeded(View view) {
if (viewZorder.contains(viewZorderIndex) && viewZorder.get(viewZorderIndex) == view) {
viewZorderIndex++;
return;
}
// Remove the views from the current z-order index to the top of the stack.
viewZorder.removeAtRange(viewZorderIndex, viewZorder.size() - 1);
viewZorder.put(viewZorderIndex, view);
viewZorderIndex++;
io.flutter.Log.d("flutter", "->" + viewZorderIndex + "- view: " + view);
view.bringToFront();
}

/**
* Called by {@code FlutterJNI} when the Flutter frame was submitted.
*
Expand Down Expand Up @@ -966,17 +1019,30 @@ public FlutterOverlaySurface createOverlaySurface() {
*
* <p>This method is used only internally by {@code FlutterJNI}.
*
* <p>This member is not intended for public use, and is only visible for testing.
* <p>This member is not intended for public use.
*/
public void destroyOverlaySurfaces() {
for (int i = 0; i < overlayLayerViews.size(); i++) {
int overlayId = overlayLayerViews.keyAt(i);
FlutterImageView overlayView = overlayLayerViews.valueAt(i);
final int overlayId = overlayLayerViews.keyAt(i);
final FlutterImageView overlayView = overlayLayerViews.valueAt(i);
overlayView.detachFromRenderer();
if (flutterView != null) {
((FlutterView) flutterView).removeView(overlayView);
}
}
overlayLayerViews.clear();
}

/** Destroys the platform views that use hybrid composition. */
@VisibleForTesting
public void destroyHybridPlatformViews() {
for (int i = 0; i < platformViewParent.size(); i++) {
final int overlayId = platformViewParent.keyAt(i);
final FlutterMutatorView view = platformViewParent.valueAt(i);
if (flutterView != null) {
((FlutterView) flutterView).removeView(view);
}
}
platformViewParent.clear();
}
}