Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@
import static io.flutter.Build.API_LEVELS;

import android.content.Context;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
Expand All @@ -43,7 +38,6 @@
import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.view.AccessibilityBridge;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
Expand Down Expand Up @@ -79,8 +73,6 @@ public class PlatformViewsController2 implements PlatformViewsAccessibilityDeleg
private Surface overlayerSurface = null;
private SurfaceControl overlaySurfaceControl = null;

private final HashSet<Integer> viewsWithPendingSurfaceCallback = new HashSet<>();

public PlatformViewsController2() {
accessibilityEventsDelegate = new AccessibilityEventsDelegate();
platformViews = new SparseArray<>();
Expand Down Expand Up @@ -508,7 +500,6 @@ public void attachToFlutterRenderer(@NonNull FlutterRenderer flutterRenderer) {
* @param mutatorsStack The mutator stack. This member is not intended for public use, and is only
* visible for testing.
*/
@RequiresApi(API_LEVELS.API_34)
public void onDisplayPlatformView(
int viewId,
int x,
Expand All @@ -533,127 +524,7 @@ public void onDisplayPlatformView(
if (view != null) {
view.setLayoutParams(layoutParams);
view.bringToFront();
if (view instanceof SurfaceView) {
maybeApplyClipToSurfaceView((SurfaceView) view, x, y, width, height, mutatorsStack, viewId);
}
}
}

@RequiresApi(API_LEVELS.API_34)
private void maybeApplyClipToSurfaceView(
SurfaceView surfaceView,
int x,
int y,
int width,
int height,
FlutterMutatorsStack mutatorsStack,
int viewId) {
// 1. CALCULATE THE FINAL RECT (RECT, RRECT, PATH, TRANSFORM)
// We start with the view's final on-screen bounds.
RectF screenRectF = new RectF(x, y, x + width, y + height);
Rect screenRect = new Rect();
screenRectF.roundOut(screenRect);

List<Path> clippingPaths = mutatorsStack.getFinalClippingPaths();

if (clippingPaths != null && !clippingPaths.isEmpty()) {
RectF pathBounds = new RectF();
for (Path path : clippingPaths) {
// Compute the axis-aligned bounding box of the path.
path.computeBounds(pathBounds, true);

// Round out to ensure we cover the pixels (ceil/floor logic).
Rect pathRectInt = new Rect();
pathBounds.roundOut(pathRectInt);

// Intersect the current visible area with this clip.
// If the path is a complex shape (star, rounded rect), this
// constrains the surface to the bounding box of that shape.
boolean anyIntersection = screenRect.intersect(pathRectInt);
if (!anyIntersection) {
screenRect.setEmpty();
break;
}
}
}

// 2. CONVERT TO LOCAL SURFACE COORDINATES
// SurfaceControl.setCrop expects coordinates relative to the Surface (0,0).
// We shift the calculated screen-space rect by the view's origin (-x, -y).
screenRect.offset(-x, -y);
if (screenRect.width() < 0 || screenRect.height() < 0) {
screenRect.setEmpty();
}

// 3. APPLY EITHER IN TIME, OR AS A CALLBACK
// If the widget tree recently changed, the SurfaceControl will likely be null.
// So apply via a SurfaceHolder.Callback(). Otherwise, apply via standard
// transaction apis.
float opacity = mutatorsStack.getFinalOpacity();
SurfaceControl sc = surfaceView.getSurfaceControl();
if (sc == null) {
if (viewsWithPendingSurfaceCallback.contains(viewId)) {
return;
}
viewsWithPendingSurfaceCallback.add(viewId);
SurfaceHolder.Callback cb =
createSurfaceClipCallback(surfaceView, opacity, screenRect, viewId);
surfaceView.getHolder().addCallback(cb);
return;
}
if (!sc.isValid()) {
Log.i(
TAG,
"Skipping applying clip to SurfaceView: "
+ surfaceView.getId()
+ " because it has an invalid SurfaceControl.");
return;
}
SurfaceControl.Transaction tx =
createTransaction().setAlpha(sc, opacity).setCrop(sc, screenRect);
}

@RequiresApi(API_LEVELS.API_34)
private SurfaceHolder.Callback createSurfaceClipCallback(
@NonNull final SurfaceView surfaceView,
final float opacity,
@NonNull final Rect screenRect,
final int viewId) {
return new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
SurfaceControl surfaceControl = surfaceView.getSurfaceControl();
if (surfaceControl != null && surfaceControl.isValid()) {
SurfaceControl.Transaction tx =
createTransaction()
.setAlpha(surfaceControl, opacity)
.setCrop(surfaceControl, screenRect);
} else {
Log.i(
TAG,
"Failed to apply clipping to SurfaceView: "
+ surfaceView.getId()
+ " - the SurfaceControl was null or invalid during surfaceCreated callback.");
}
// Because this transaction is created outside of the frame timing, we can't
// guarantee there is another frame coming (if, say, the app has a static
// layout). So we schedule one to ensure the crop is rendered properly.
// See https://github.com/flutter/flutter/issues/175546.
flutterJNI.scheduleFrame();
viewsWithPendingSurfaceCallback.remove(viewId);
surfaceView.getHolder().removeCallback(this);
}

@Override
public void surfaceChanged(
@NonNull SurfaceHolder holder, int format, int width, int height) {}

@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
viewsWithPendingSurfaceCallback.remove(viewId);
surfaceView.getHolder().removeCallback(this);
}
};
}

public void hidePlatformView(int viewId) {
Expand Down Expand Up @@ -768,7 +639,6 @@ public void createPlatformView(@NonNull PlatformViewCreationRequest request) {

@Override
public void dispose(int viewId) {
viewsWithPendingSurfaceCallback.remove(viewId);
final PlatformView platformView = platformViews.get(viewId);
if (platformView == null) {
Log.e(TAG, "Disposing unknown platform view with id: " + viewId);
Expand Down